Posted to tcl by hypnotoad at Tue Oct 09 23:50:43 GMT 2018view raw

  1. /*
  2. ** This file is generated by the /Users/seandeelywoods/build/odie/odielib/make.tcl script
  3. ** any changes will be overwritten the next time it is run
  4. */
  5.  
  6. /* This file was generated by practcl */
  7.  
  8. #include <tcl.h>
  9. #include <tclOO.h>
  10. #include "odielibc.h"
  11. #include <assert.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <stdlib.h>
  15. #include "inline_list.h"
  16. #include <limits.h>
  17. #include <float.h>
  18. #include <strings.h>
  19. /* BEGIN generate-cfile-header */
  20. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/hash/hash.tcl generate-cfile-header */
  21. /****** This file is copied from SQLite and modified *******
  22. **
  23. ** 2001 September 22
  24. **
  25. ** The author disclaims copyright to this source code. In place of
  26. ** a legal notice, here is a blessing:
  27. **
  28. ** May you do good and not evil.
  29. ** May you find forgiveness for yourself and forgive others.
  30. ** May you share freely, never taking more than you give.
  31. **
  32. *************************************************************************
  33. ** This is the implementation of generic hash-tables
  34. ** used in SQLite.
  35. **
  36. */
  37. #define uptr unsigned int
  38. #define Addr(X) ((uptr)X)
  39. #define readiMalloc malloc
  40. #define readiFree free
  41. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/hash/hash.tcl generate-cfile-header */
  42. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/btree/btree.tcl generate-cfile-header */
  43. static void TreeClearNode(TreeElem *p, void (*xFree)(void*));
  44. static TreeElem *TreeFindNthElem(Tree *tree, int n);
  45. static void TreeBalance(TreeElem **ppElem);
  46. static void *TreeInsertElement(Tree *pTree, void *key, void *data);
  47. static TreeElem *TreeDeleteNthElem(TreeElem **ppTop, int N);
  48. static TreeElem *TreeDeleteElem(Tree *tree, const void *key);
  49. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/btree/btree.tcl generate-cfile-header */
  50. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/odiemath/odiemath.tcl generate-cfile-header */
  51. double OdieGrain=2.5;
  52. double OdieTolerance=0.001;
  53. static inline int Odie_GetMatrixElementFromObj(Tcl_Interp *interp,Tcl_Obj *objPtr,double *R,int idx);
  54. static inline unsigned int hashInt(int x);
  55. static inline long intCoord(double x);
  56. static inline unsigned int hashPoint(VECTORXY p);
  57. static inline unsigned int hashVectorXY(VECTORXY p);
  58. static inline unsigned int hashVectorXYZ(VECTORXYZ p);
  59. static inline double roundCoord(double x);
  60. static inline int hashCoord(double x, double y);
  61. static inline int hashCoord3d(double x, double y,double z);
  62. static inline int floatCompare(double x0, double x1);
  63. static inline void GridCoord(double *x, double *y);
  64. static int TclCmd_odiemath_distance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  65. static int TclCmd_odiemath_dist3d(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  66. static int TclCmd_odiemath_grid_hex(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  67. static int TclCmd_odiemath_grid_round(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  68. static int TclCmd_odiemath_grid_square(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  69. static int TclCmd_odiemath_list_round(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  70. static int TclCmd_odiemath_list_to_int(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  71. static int TclCmd_odiemath_matrix_rotate_angle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  72. static int TclCmd_odiemath_matrix_rotate_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  73. static int TclCmd_odiemath_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  74. static int TclCmd_odiemath_perpendicular(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  75. static int TclCmd_odiemath_normal_2d(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  76. static int TclCmd_odiemath_parallel_segment(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  77. static int TclCmd_odiemath_vector_length(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  78. static int TclCmd_odiemath_vector_rotate_and_size(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  79. static int TclCmd_odiemath_vector_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  80. static int TclCmd_odiemath_vector_translate_and_zoom(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  81. static int TclCmd_odiemath_grid(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  82. static int TclCmd_odiemath_tolerance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  83. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/odiemath/odiemath.tcl generate-cfile-header */
  84. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/module.ini generate-cfile-header */
  85. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/aabb.tcl generate-cfile-header */
  86. static inline void VectorXYZ_AABB_Normalize(AABBXYZ R);
  87. static void VectorXYZ_AABB_Copy(AABBXYZ dest,AABBXYZ src);
  88. static inline int VectorXYZ_AABB_Within(VectorXYZ POINT,AABBXYZ R);
  89. static inline int VectorXYZ_BBOX_Overlap_TwoVectors(VectorXYZ A1,VectorXYZ A2,VectorXYZ B1,VectorXYZ B2);
  90. static inline int AABB_AABB_Intersect(AABBXYZ A,AABBXYZ B);
  91. static inline void VectorXYZ_AABB_Measure(VectorXYZ POINT,AABBXYZ R);
  92. static inline void AABB_AABB_Combine(AABBXYZ B,AABBXYZ A);
  93. static inline void VectorXYZ_AABB_Reset(AABBXYZ R);
  94. static int TclCmd_odie_aabb_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  95. static int TclCmd_odie_aabb_overlap_two_vectors(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  96. static int TclCmd_odie_aabb_measure(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  97. static int TclCmd_odie_aabb_faces(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  98. static int TclCmd_odie_aabb_from_vectorxyz(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  99. static int TclCmd_odie_aabb_from_line(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  100. static int TclCmd_odie_aabb_from_center_size(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  101. static int TclCmd_odie_aabb_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  102. static int TclCmd_odie_aabb_within(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  103. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/aabb.tcl generate-cfile-header */
  104. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/affine2d.tcl generate-cfile-header */
  105. static int TclCmd_affine2d_apply(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  106. static int TclCmd_affine2d_combine(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  107. static int TclCmd_affine2d_rotation_from_angle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  108. static int TclCmd_affine2d_rotation_from_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  109. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/affine2d.tcl generate-cfile-header */
  110. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/affine3d.tcl generate-cfile-header */
  111. static inline int affine_Compare(AFFINE A,AFFINE B);
  112. static inline void affine_rotate_spin(AFFINE RESULT,SCALER psi);
  113. static void Odie_Affine_From_Normal(AFFINE RESULT,VectorXYZ NORMAL);
  114. static int TclCmd_affine4x4_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  115. static int TclCmd_affine4x4_identity(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  116. static int TclCmd_affine4x4_translation(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  117. static int TclCmd_affine4x4_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  118. static int TclCmd_affine4x4_rotate_nutation(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  119. static int TclCmd_affine4x4_rotate_precession(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  120. static int TclCmd_affine4x4_rotate_spin(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  121. static int TclCmd_affine4x4_from_euler(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  122. static int TclCmd_affine4x4_multiply(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  123. static int TclCmd_affine4x4_multiply_inplace(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  124. static int TclCmd_affine4x4_inverse(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  125. static int TclCmd_affine4x4_from_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  126. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/affine3d.tcl generate-cfile-header */
  127. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/bbox.tcl generate-cfile-header */
  128. static inline void VectorXY_BBOX_Copy(BBOXXY dest,BBOXXY src);
  129. static inline void VectorXY_BBOX_Reset(BBOXXY R);
  130. static inline int VectorXY_IsBetween_BBOX(VectorXY POINT,VectorXY A,VectorXY B);
  131. static inline int VectorXY_Within_BBOX(VectorXY POINT,BBOXXY bbox);
  132. static inline int XY_Within_BBOX(double x, double y,BBOXXY bbox);
  133. static inline void VectorXY_BBOX_Measure(VectorXY POINT,BBOXXY bbox);
  134. static inline int BBOX_BBOX_Intersect(BBOXXY A,BBOXXY B);
  135. static int TclCmd_odie_bbox_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  136. static int TclCmd_odie_bbox_measure(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  137. static int TclCmd_odie_bbox_elements(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  138. static int TclCmd_odie_bbox_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  139. static int TclCmd_odie_bbox_within(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  140. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/bbox.tcl generate-cfile-header */
  141. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/quaternion.tcl generate-cfile-header */
  142. static inline void Quaternion_From_Normal(QUATERNION RESULT,VectorXYZ from,VectorXYZ to);
  143. static int TclCmd_quaternion_add(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  144. static int TclCmd_quaternion_subtract(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  145. static int TclCmd_quaternion_multiply(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  146. static int TclCmd_quaternion_divide(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  147. static int TclCmd_quaternion_square_root(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  148. static int TclCmd_quaternion_square(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  149. static int TclCmd_quaternion_from_euler(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  150. static int TclCmd_vectorxyz_rotate_by_quaternion(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  151. static int TclCmd_quaternion_to_euler(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  152. static int TclCmd_quaternion_from_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  153. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/quaternion.tcl generate-cfile-header */
  154. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vector.tcl generate-cfile-header */
  155. static double Vector_Tolerance=0.01;
  156. static double Vector_Tolerance_Sq=0.0001;
  157. static Odie_MatrixObj *Odie_Matrix_To_Fit(Odie_MatrixObj *A,Odie_MatrixObj *B);
  158. static inline double Vector_GridScaler(double x,double grid,double grain);
  159. static int TclCmd_odie_tolerance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  160. static int TclCmd_odie_vector_to_list(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  161. static int TclCmd_odie_vector_index(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  162. static int TclCmd_odie_vector_add(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  163. static int TclCmd_odie_vector_is_null(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  164. static int TclCmd_odie_vector_subtract(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  165. static int TclCmd_odie_vector_midpoint(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  166. static int TclCmd_odie_vector_reciprocal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  167. static int TclCmd_odie_vector_dot_product(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  168. static int TclCmd_odie_vector_to_matrix(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  169. static int TclCmd_odie_vector_to_fuzzy(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  170. static int TclCmd_odie_vector_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  171. static int TclCmd_odie_vector_length(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  172. static int TclCmd_odie_vector_length_squared(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  173. static int TclCmd_odie_grid(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  174. static int TclCmd_odie_gridvar(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  175. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vector.tcl generate-cfile-header */
  176. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vector2d.tcl generate-cfile-header */
  177. /*
  178. ** Routines in this file are designed to work with double numbers
  179. ** directly. Useful for screen operations where X Y lists are used
  180. */
  181. static inline int Vector2d_PointIsOnSegment(double x,double y,double x1,double y1,double x2,double y2);
  182. static int TclCmd_vector2d_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  183. static int TclCmd_vector2d_add(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  184. static int TclCmd_vector2d_subtract(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  185. static int TclCmd_vector2d_midpoint(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  186. static int TclCmd_vector2d_affine_apply(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  187. static int TclCmd_vector2d_angle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  188. static int TclCmd_vector2d_distance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  189. static int TclCmd_vector2d_dotproduct(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  190. static int TclCmd_vector2d_crossproduct(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  191. static int TclCmd_vector2d_rightof(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  192. static int TclCmd_vector2d_rotate_and_size(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  193. static int TclCmd_vector2d_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  194. static int TclCmd_vector2d_translate_and_zoom(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  195. static int TclCmd_vector2d_point_on_segment(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  196. static int TclCmd_vector2d_line_circle_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  197. static int TclCmd_vector2d_line_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  198. static int TclCmd_vector2d_line_overlap(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  199. static int TclCmd_vector2d_colinear(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  200. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vector2d.tcl generate-cfile-header */
  201. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vector3d.tcl generate-cfile-header */
  202. static int TclCmd_vector3d_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  203. static int TclCmd_vector3d_add(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  204. static int TclCmd_vector3d_subtract(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  205. static int TclCmd_vector3d_orthagonal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  206. static int TclCmd_vector3d_distance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  207. static int TclCmd_vector3d_distanceSq(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  208. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vector3d.tcl generate-cfile-header */
  209. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vectorn.tcl generate-cfile-header */
  210. static int TclCmd_vectorN_length(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  211. static int TclCmd_vectorN_distance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  212. static int TclCmd_vectorN_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  213. static int TclCmd_vectorN_scalevar(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  214. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vectorn.tcl generate-cfile-header */
  215. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vectorxy.tcl generate-cfile-header */
  216. static inline void VectorXY_GridAlign(VECTORXYZ A,double grid);
  217. static inline void VectorXY_Midpoint(VECTORXY C,VECTORXY A,VECTORXY B);
  218. static int TclCmd_vectorxy_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  219. static int TclCmd_vectorxy_add(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  220. static int TclCmd_vectorxy_subtract(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  221. static int TclCmd_vectorxy_midpoint(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  222. static int TclCmd_vectorxy_add_stream(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  223. static int TclCmd_vectorxy_angle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  224. static int TclCmd_vectorxy_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  225. static int TclCmd_vectorxy_toint(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  226. static int TclCmd_vectorxy_crossproduct(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  227. static int TclCmd_vectorxy_distance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  228. static int TclCmd_vectorxy_length(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  229. static int TclCmd_vectorxy_normalize(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  230. static int TclCmd_vectorxy_dotproduct(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  231. static int TclCmd_vectorxy_rightof(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  232. static int TclCmd_vectorxy_rotate_and_size(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  233. static int TclCmd_vectorxy_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  234. static int TclCmd_vectorxy_translate_and_zoom(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  235. static int TclCmd_vectorxy_flatten(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  236. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vectorxy.tcl generate-cfile-header */
  237. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vectorxyz.tcl generate-cfile-header */
  238. static inline void VectorXYZ_Scale(VECTOR A,SCALER S);
  239. static inline void VectorXYZ_Zero(VECTORXYZ A);
  240. static inline void VectorXYZ_GridAlign(VECTORXYZ A,double grid);
  241. static inline void VectorXYZ_Copy(VECTORXYZ B,VECTORXYZ A);
  242. static inline int VectorXYZ_SamePoint(VECTORXYZ A,VECTORXYZ B);
  243. static inline int VectorXYZ_IsZero(VECTORXYZ A);
  244. static inline void VectorXYZ_Cross_Product(VectorXYZ C,VectorXYZ A,VectorXYZ B);
  245. static inline void VectorXYZ_Add(VECTORXYZ C,VECTORXYZ A,VECTORXYZ B);
  246. static inline void VectorXYZ_Subtract(VECTORXYZ C,VECTORXYZ A,VECTORXYZ B);
  247. static inline int VectorXYZ_IsOrthagonal(VECTORXYZ A,VECTORXYZ B);
  248. static inline void VectorXYZ_Midpoint(VECTORXYZ C,VECTORXYZ A,VECTORXYZ B);
  249. static inline double VectorXYZ_Distance(VECTORXYZ A,VECTORXYZ B);
  250. static inline double VectorXYZ_DistanceSq(VECTORXYZ A,VECTORXYZ B);
  251. static inline double VectorXYZ_Dot_Product(VectorXYZ A,VectorXYZ B);
  252. static inline void VectorXYZ_MatrixMultiply(VECTORXYZ R,VECTORXYZ A,AFFINE M);
  253. static inline double VectorXYZ_MagnitudeSq(VECTOR A);
  254. static inline double VectorXYZ_Magnitude(VECTOR A);
  255. static inline double VectorXYZ_MagnitudeInvSqr(VECTOR A);
  256. static inline int VectorXYZ_Normalize(VectorXYZ A);
  257. static inline int VectorXYZ_PointIsOnSegment(VectorXYZ POINT,VectorXYZ A,VectorXYZ B);
  258. static inline int VectorXYZ_AxisOfNormal(VectorXYZ NORMAL);
  259. static inline int VectorXYZ_NormalStrictAxisAligned(VectorXYZ NORMAL);
  260. static inline int VectorXYZ_AxisAligned(VectorXYZ A,VectorXYZ B,VectorXYZ C);
  261. static inline int VectorXYZ_BendDirection(VectorXYZ A,VectorXYZ B,VectorXYZ C);
  262. static inline double VectorXYZ_Angle_Three_Point(VectorXYZ A,VectorXYZ B,VectorXYZ C,VectorXYZ normal);
  263. static inline int VectorXYZ_IsColinear(VectorXYZ A,VectorXYZ B,VectorXYZ C);
  264. static inline int VectorXYZ_IsCoplaner(VectorXYZ x1,VectorXYZ x2,VectorXYZ x3,VectorXYZ x4);
  265. static inline int VectorXYZ_LineLineCoincident(
  266. VectorXYZ A1, VectorXYZ A2, VectorXYZ B1, VectorXYZ B2,
  267. VectorXYZ ICEPT1, VectorXYZ ICEPT2
  268. );
  269. static inline int VectorXYZ_LineLineIntersect(
  270. VectorXYZ p1, VectorXYZ p2, VectorXYZ p3, VectorXYZ p4,
  271. VectorXYZ pA, VectorXYZ pB, double *mua, double *mub
  272. );
  273. static double VectorXYZ_ClosestPointOnSegment (
  274. VectorXYZ A, VectorXYZ B, /* End points of the line segment */
  275. VectorXYZ X, /* The point outside the line */
  276. VectorXYZ R /* Write closest point on line segment here */
  277. );
  278. static int VectorXYX_solve3by3(double *m);
  279. static double VectorXYZ_TriangleLineIntersect(
  280. VectorXYZ A, VectorXYZ B, VectorXYZ C, /* The triangle we are trying to intersect */
  281. VectorXYZ pStart, /* Start of the line segment */
  282. VectorXYZ pEnd, /* End of the line segment */
  283. VectorXYZ pIntersect /* Point of intersection written here if not NULL */
  284. );
  285. static inline void VectorXYZ_Normal_of_Three_Points(VectorXYZ normal,VectorXYZ A,VectorXYZ B,VectorXYZ C);
  286. static int TclCmd_vectorxyz_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  287. static int TclCmd_vectorxyz_zero(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  288. static int TclCmd_vectorxyz_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  289. static int TclCmd_vectorxyz_polygon_normal_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  290. static int TclCmd_vectorxyz_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  291. static int TclCmd_vectorxyz_toint(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  292. static int TclCmd_vectorxyz_add(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  293. static int TclCmd_vectorxyz_add_inplace(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  294. static int TclCmd_vectorxyz_orthagonal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  295. static int TclCmd_vectorxyz_subtract(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  296. static int TclCmd_vectorxyz_midpoint(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  297. static int TclCmd_vectorxyz_cross_product(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  298. static int TclCmd_vectorxyz_dot_product(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  299. static int TclCmd_vectorxyz_transform(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  300. static int TclCmd_vectorxyz_length(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  301. static int TclCmd_vectorxyz_distance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  302. static int TclCmd_vectorxyz_distanceSq(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  303. static int TclCmd_vectorxyz_length_inv_sqr(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  304. static int TclCmd_vectorxyz_normalize(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  305. static int TclCmd_vectorxyz_point_on_segment(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  306. static int TclCmd_vectorxyz_point_on_segment_x(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  307. static int TclCmd_vectorxyz_axis_of_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  308. static int TclCmd_vectorxyz_bend_direction(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  309. static int TclCmd_vectorxyz_angle_three_points(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  310. static int TclCmd_vectorxyz_colinear(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  311. static int TclCmd_vectorxyz_coplaner(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  312. static int TclCmd_vectorxyz_linelinecoincident_int(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  313. static int TclCmd_vectorxyz_linelinecoincident(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  314. static int TclCmd_vectorxyz_linelineintersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  315. static int TclCmd_vectorxyz_linelineintersect_distance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  316. static int TclCmd_vectorxyz_sizeof(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  317. static int TclCmd_vectorxyz_closest_point_on_segment(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  318. static int TclCmd_vectorxyz_point_in_triangle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  319. static int TclCmd_vectorxyz_triangle_line_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  320. static int TclCmd_vectorxyz_line_sphere_intersect_length(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  321. static int TclCmd_vectorxyz_line_sphere_intersect_area(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  322. static int TclCmd_vectorxyz_line_sphere_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  323. static int TclCmd_vectorxyz_polygon_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  324. static int TclCmd_vectorxyz_polygon_center(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  325. static int TclCmd_vectorxyz_flatten(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  326. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/vectorxyz.tcl generate-cfile-header */
  327. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/affine/cmatrixforms.tcl generate-cfile-header */
  328. const MatrixForm MatrixForms[] = {
  329. { MATFORM_null, "null", 0 , 0, "A matrix of arbitrary size", NULL },
  330. { MATFORM_aabb_xyz, "aabb_xyz", 6, 1, "An axis aligned bounding box in 3 dimensions", NULL },
  331. { MATFORM_affine, "affine", 4, 4, "A 4x4 affine matrix", Matrix_To_affine },
  332. { MATFORM_bbox_xy, "bbox_xy", 4, 1, "A 2 dimensional vector: X Y", Matrix_To_cartesian },
  333. { MATFORM_cylindrical, "cylindrical", 3, 1, "A 3 dimensional vector: RADIUS THETA Z", Matrix_To_cylindrical },
  334. { MATFORM_euler, "euler", 3, 1, "A 3 dimensional rotation: X Y Z", NULL },
  335. { MATFORM_heading, "heading", 3, 1, "A 3 dimensional rotation: yaw pitch roll", NULL },
  336. { MATFORM_mat2, "mat2", 2, 2, "A 2x2 matrix", NULL },
  337. { MATFORM_mat3, "mat3", 3, 3, "A 3x3 matrix", NULL },
  338. { MATFORM_mat4, "mat4", 4, 4, "A 4x4 matrix", NULL },
  339. { MATFORM_polar, "polar", 2, 1, "A 2 dimensional vector: RADIUS THETA", Matrix_To_cylindrical },
  340. { MATFORM_quaternion, "quaternion", 4, 1, "A quaternion: W X Y Z", Matrix_To_quaternion },
  341. { MATFORM_scaler, "scaler", 1, 1, "A scaler (1x1)", NULL },
  342. { MATFORM_spherical, "spherical", 3, 1, "A 3 dimensional vector: RADIUS THETA PHI", Matrix_To_spherical },
  343. { MATFORM_unknown, "unknown", 0 , 0, "A matrix of arbitrary size (but less than 4x4)", NULL },
  344. { MATFORM_vector_xy, "vector_xy", 2, 1, "A 2 dimensional vector: X Y", Matrix_To_cartesian },
  345. { MATFORM_vector_xyz, "vector_xyz", 3, 1, "A 3 dimensional vector: X Y Z", Matrix_To_cartesian },
  346. { MATFORM_vector_xyzw, "vector_xyzw", 4, 1, "A 4 dimensional vector: X Y Z W", Matrix_To_cartesian }
  347. };
  348. /* Module wide constants */
  349. const Tcl_ObjType *NumArrayType;
  350. const Tcl_ObjType *odieMatrixType;
  351. static int TclCmd_matrix_to_aabb_xyz(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  352. static int TclCmd_matrix_to_affine(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  353. static int TclCmd_matrix_to_bbox_xy(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  354. static int TclCmd_matrix_to_cylindrical(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  355. static int TclCmd_matrix_to_euler(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  356. static int TclCmd_matrix_to_heading(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  357. static int TclCmd_matrix_to_mat2(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  358. static int TclCmd_matrix_to_mat3(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  359. static int TclCmd_matrix_to_mat4(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  360. static int TclCmd_matrix_to_null(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  361. static int TclCmd_matrix_to_polar(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  362. static int TclCmd_matrix_to_quaternion(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  363. static int TclCmd_matrix_to_scaler(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  364. static int TclCmd_matrix_to_spherical(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  365. static int TclCmd_matrix_to_unknown(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  366. static int TclCmd_matrix_to_vector_xy(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  367. static int TclCmd_matrix_to_vector_xyz(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  368. static int TclCmd_matrix_to_vector_xyzw(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  369. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/cmatrixforms.tcl generate-cfile-header */
  370. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/affine/module.ini generate-cfile-header */
  371. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/fuzzy/fuzzy.tcl generate-cfile-header */
  372. #ifdef _MSC_VER
  373. # define Odie_IsInfinite(d) (!(_finite((d))))
  374. # define Odie_IsNaN(d) (_isnan((d)))
  375. #else
  376. # define Odie_IsInfinite(d) ((d) > DBL_MAX || (d) < -DBL_MAX)
  377. # ifdef NO_ISNAN
  378. # define Odie_IsNaN(d) ((d) != (d))
  379. # else
  380. # define Odie_IsNaN(d) (isnan(d))
  381. # endif
  382. #endif
  383.  
  384. static int TclCmd_tcl_mathfunc_to_fuzzy(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  385. static int TclCmd_tcl_mathfunc_fuzzy_abs(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  386. static int TclCmd_tcl_mathfunc_fuzzy_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  387. static int TclCmd_tcl_mathfunc_fuzzy_is_zero(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  388. static int TclCmd_tcl_mathfunc_fuzzy_gt_zero(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  389. static int TclCmd_tcl_mathfunc_fuzzy_epsilon(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  390. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/fuzzy/fuzzy.tcl generate-cfile-header */
  391. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/module.ini generate-cfile-header */
  392. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/triangulate.tcl generate-cfile-header */
  393. #ifndef IRM_EPSILON
  394. #define IRM_EPSILON FLT_EPSILON
  395. #endif
  396.  
  397. #ifndef M_PI
  398. # define M_PI 3.1415926535898
  399. #endif
  400.  
  401. static int TclCmd_triag_test_rightof(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  402. static int TclCmd_triag_test_dotprod(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  403. static int TclCmd_triag_test_angle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  404. static int TclCmd_triag_test_ideal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  405. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/triangulate.tcl generate-cfile-header */
  406. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/polygon.tcl generate-cfile-header */
  407. static inline int Odie_IsColinear(double x1,double y1,double x2,double y2,double x3,double y3);
  408. static inline double dist(double x0, double y0, double x1, double y1);
  409. static inline int withinPolygon(Odie_Polygon *p, double x, double y);
  410. static int TclCmd_polygon_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  411. static int TclCmd_polygon_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  412. static int TclCmd_polygon_simplify(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  413. static int TclCmd_polygon_area(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  414. static int TclCmd_polygon_bbox(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  415. static int TclCmd_polygon_info(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  416. static int TclCmd_polygon_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  417. static int TclCmd_polygon_within(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  418. static int TclCmd_polygon_center(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  419. static int TclCmd_polygon_canvascoords(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  420. static int TclCmd_polygon_coords(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  421. static int TclCmd_polygon_xycoords(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  422. static int TclCmd_polygon_edges(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  423. static int TclCmd_polygon_bend(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  424. static int TclCmd_polygon_is_convex(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  425. static int TclCmd_polygon_segments(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  426. static int TclCmd_polygon_rectangle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  427. static int TclCmd_polygon_vector_place(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  428. static int TclCmd_polygon_hexagon(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  429. static int TclCmd_polygon_poly_place(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  430. static int TclCmd_polygon_drawobj_orientation(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  431. static int TclCmd_polygon_corners(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  432. static int TclCmd_polygon_hexgrid_location(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  433. static int TclCmd_polygon_hexgrid_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  434. static int TclCmd_polygon_squaregrid_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  435. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/polygon.tcl generate-cfile-header */
  436. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/polygonxyz.tcl generate-cfile-header */
  437. static inline int Odie_FaceXYZ_Compare(Odie_FaceXYZ *A,Odie_FaceXYZ *B);
  438. static inline int Odie_FaceXYZ_Coplaner(Odie_FaceXYZ *A,Odie_FaceXYZ *B);
  439. static inline int PolygonUV_Within(Odie_FaceXYZ *p, double x, double y);
  440. static inline int Odie_FaceXYZ_Within(Odie_FaceXYZ *p, VectorXYZ POINT);
  441. static int Odie_FaceXYZ_IntersectTest(Odie_FaceXYZ *p1,Odie_FaceXYZ *p2);
  442. static double Odie_FaceXYZ_AreaOfIntersection(Odie_FaceXYZ *p1,Odie_FaceXYZ *p2,double *xin,double *yin);
  443. static int TclCmd_polygonxyz_info(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  444. static int TclCmd_polygonxyz_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  445. static int TclCmd_polygonxyz_createxy(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  446. static int TclCmd_polygonxyz_simplify(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  447. static int TclCmd_polygonxyz_id(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  448. static int TclCmd_polygonxyz_area(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  449. static int TclCmd_polygonxyz_bbox(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  450. static int TclCmd_polygonxyz_bend(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  451. static int TclCmd_polygonxyz_center(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  452. static int TclCmd_polygonxyz_is_2d(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  453. static int TclCmd_polygonxyz_is_convex(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  454. static int TclCmd_polygonxyz_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  455. static int TclCmd_polygonxyz_nVertex(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  456. static int TclCmd_polygonxyz_radius(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  457. static int TclCmd_polygonxyz_rotation(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  458. static int TclCmd_polygonxyz_rotation_inv(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  459. static int TclCmd_polygonxyz_axis_of_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  460. static int TclCmd_polygonxyz_canvascoords(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  461. static int TclCmd_polygonxyz_coords(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  462. static int TclCmd_polygonxyz_intcoordsxy(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  463. static int TclCmd_polygonxyz_intcoords(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  464. static int TclCmd_polygonxyz_edges(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  465. static int TclCmd_polygonxyz_triangles(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  466. static int TclCmd_polygonxyz_uvcoords(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  467. static int TclCmd_polygonxyz_xycoords(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  468. static int TclCmd_polygonxyz_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  469. static int TclCmd_polygonxyz_coplaner(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  470. static int TclCmd_polygonxyz_flipped(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  471. static int TclCmd_polygonxyz_side(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  472. static int TclCmd_polygonxyz_intersect_test(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  473. static int TclCmd_polygonxyz_intersect_test_uv(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  474. static int TclCmd_polygonxyz_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  475. static int TclCmd_polygonxyz_intersect_uv(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  476. static int TclCmd_polygonxyz_points_within(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  477. static int TclCmd_polygonxyz_within(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  478. static int TclCmd_polygonxyz_within_set(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  479. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/polygonxyz.tcl generate-cfile-header */
  480. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/segset.tcl generate-cfile-header */
  481. static void SegmentSet_Delete(ClientData clientData);
  482. static int SegmentSet_Clone(
  483. Tcl_Interp* interp, /* Tcl interpreter for error reporting */
  484. ClientData metadata, /* Metadata to be cloned */
  485. ClientData* newMetaData /* Where to put the cloned metadata */
  486. );
  487. static int SegmentSet_Cleanup_Coincident(SegmentSet *pSet,Segment *pAB);
  488. static int Segment_OnList(Segment *pSeg, Link *pList);
  489. static Segment *SegmentSet_FindById(SegmentSet *p, int id);
  490. static void Segment_Imprint(Segment *pSrc,Segment *pDest);
  491. static void Segment_SetToFrom(SegmentSet *pSet, Segment *p, VECTORXYZ from, VECTORXYZ to);
  492. static inline Segment *Segment_Create(SegmentSet *pSet,int newid);
  493. static inline void SegmentSetRemove(SegmentSet *pSet, Segment *p);
  494. static inline void SegRelink(SegmentSet *pSet, Segment *p);
  495. static inline void SegmentSetClear(SegmentSet *pSet);
  496. static inline void SegmentSetStep(SegmentSet *pSet);
  497. static int SegmentSet_AddVertex(SegmentSet *pSet,VectorXYZ A);
  498. static int SegmentSet_Interference_Check(SegmentSet *pSet,VectorXYZ A,VectorXYZ B);
  499. static int SegmentSet_Edge_Connection(SegmentSet *pSet,VectorXYZ A,int comptid,VectorXYZ RESULT);
  500. static int SegmentSet_Convex_Connection(SegmentSet *pSet,Segment *pAB,int back,VectorXYZ RESULT);
  501. static int SegmentSetNextBend(
  502. SegmentSet *pSet,
  503. Segment *pAB,
  504. int backwards,
  505. Segment **ppSeg, /* OUT: First segment clockwise from xR,yR->xV,yV */
  506. int *pfBack, /* OUT: True if output segment goes backwards */
  507. int *pfBend, /* OUT: Bend direction */
  508. double *pfAngle
  509. );
  510. static int SegmentSet_SelfCheck(Tcl_Interp *interp, SegmentSet *p);
  511. static Link *SegmentSet_Segments_AtVertex(SegmentSet *p, VectorXYZ point,int *nSeg);
  512. static int SegmentSetNext(
  513. SegmentSet *pSet,
  514. Segment *pAB,
  515. int backwards,
  516. Segment **ppSeg, /* OUT: First segment clockwise from xR,yR->xV,yV */
  517. int *pfBack, /* OUT: True if output segment goes backwards */
  518. int *pfBend, /* OUT: Bend direction */
  519. double *pfAngle
  520. );
  521. static void SegmentSet_ClearFaceEdgeCache(SegmentSet *pSet);
  522. static void FaceBoundary_Mark_Degenerate(FaceBoundary *pFace,int code);
  523. static int SegmentSet_BuildFaceEdgeCache_ExpandRight(SegmentSet *pSet,int faceid,int stage);
  524. static void SegmentSet_BuildFaceEdgeCache(SegmentSet *pSet);
  525. static int OOMethod_SegmentSet_segment_info(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  526. static int OOMethod_SegmentSet_SegmentSet_Init(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  527. static int OOMethod_SegmentSet_modified(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  528. static int OOMethod_SegmentSet_segment_count(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  529. static int OOMethod_SegmentSet_bbox(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  530. static int OOMethod_SegmentSet_segment_reset(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  531. static int OOMethod_SegmentSet_segment_add(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  532. static int OOMethod_SegmentSet_segment_add_virtual(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  533. static int OOMethod_SegmentSet_polygon_add(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  534. static int OOMethod_SegmentSet_vertex_add(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  535. static int OOMethod_SegmentSet_segment_delete(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  536. static int OOMethod_SegmentSet_delete(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  537. static int OOMethod_SegmentSet_cleanup(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  538. static int OOMethod_SegmentSet_cleanup_looseend(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  539. static int OOMethod_SegmentSet_edge_connection(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  540. static int OOMethod_SegmentSet_check_intersecting(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  541. static int OOMethod_SegmentSet_check_coincident(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  542. static int OOMethod_SegmentSet_segment_linelineintersect(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  543. static int OOMethod_SegmentSet_segment_coincident(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  544. static int OOMethod_SegmentSet_segment_find(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  545. static int OOMethod_SegmentSet_vertex_delete(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  546. static int OOMethod_SegmentSet_segment_next(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  547. static int OOMethod_SegmentSet_check_oblique(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  548. static int OOMethod_SegmentSet_check_looseends(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  549. static int OOMethod_SegmentSet_fix_looseends(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  550. static int OOMethod_SegmentSet_grid(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  551. static int OOMethod_SegmentSet_segment_list(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  552. static int OOMethod_SegmentSet_segment_coords(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  553. static int OOMethod_SegmentSet_segment_uvcoords(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  554. static int OOMethod_SegmentSet_selfcheck(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  555. static int OOMethod_SegmentSet_uv_transform(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  556. static int OOMethod_SegmentSet_polygons_xyz(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  557. static int OOMethod_SegmentSet_polygons(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  558. static int OOMethod_SegmentSet_polygon_faces(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  559. static int OOMethod_SegmentSet_polygon_info(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  560. static int SegmentSet_OO_Init(Tcl_Interp *interp);
  561. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/segset.tcl generate-cfile-header */
  562. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/shapes.tcl generate-cfile-header */
  563. static int TclCmd_shapes_corners(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  564. static int TclCmd_shapes_drawobj_orientation(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  565. static int TclCmd_shapes_poly_hex(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  566. static int TclCmd_shapes_poly_place(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  567. static int TclCmd_shapes_polygon_to_vectors(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  568. static int TclCmd_shapes_rectangle_as_polygon(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  569. static int TclCmd_shapes_rectangle_as_vectors(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  570. static int TclCmd_shapes_vector_place(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  571. static int TclCmd_shapes_hexagon(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  572. static int TclCmd_shapes_canvas(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  573. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/shapes.tcl generate-cfile-header */
  574. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/plotter.tcl generate-cfile-header */
  575. static void Plotter_Delete(ClientData clientData);
  576. static int Plotter_Clone(
  577. Tcl_Interp* interp, /* Tcl interpreter for error reporting */
  578. ClientData metadata, /* Metadata to be cloned */
  579. ClientData* newMetaData /* Where to put the cloned metadata */
  580. );
  581. static inline double Plotter_xCanvasToActual(Plotter *p,double cx);
  582. static inline double Plotter_yCanvasToActual(Plotter *p,double cy);
  583. static inline double Plotter_xActualToCanvas(Plotter *p,double ax);
  584. static inline double Plotter_yActualToCanvas(Plotter *p,double ay);
  585. static int OOMethod_Plotter_actualcoords(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  586. static int OOMethod_Plotter_canvascoords(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  587. static int OOMethod_Plotter_centerset(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  588. static int OOMethod_Plotter_xoffset(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  589. static int OOMethod_Plotter_yoffset(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  590. static int OOMethod_Plotter_zoom(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  591. static int OOMethod_Plotter_constructor(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  592. static int Plotter_OO_Init(Tcl_Interp *interp);
  593. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/plotter.tcl generate-cfile-header */
  594. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/slicer.tcl generate-cfile-header */
  595. static void Slicer_Delete(ClientData clientData);
  596. static int Slicer_Clone(
  597. Tcl_Interp* interp, /* Tcl interpreter for error reporting */
  598. ClientData metadata, /* Metadata to be cloned */
  599. ClientData* newMetaData /* Where to put the cloned metadata */
  600. );
  601. static double Slicer_xCanvasToActual(Slicer *p,struct OneSlice *pS, double cx);
  602. static double Slicer_yCanvasToActual(Slicer *p,struct OneSlice *pS, double cy);
  603. static double Slicer_xActualToCanvas(Slicer *p,struct OneSlice *pS, double ax);
  604. static double Slicer_yActualToCanvas(Slicer *p,struct OneSlice *pS, double ay);
  605. static double Slicer_deckHeight(struct OneSlice *p, double rX);
  606. static struct OneSlice *Slicer_deckAt(Slicer *p, double rX, double rZ);
  607. static struct OneSlice *Slicer_deckAbove(Slicer *p, struct OneSlice *pRef);
  608. static struct OneSlice *Slicer_deckBelow(Slicer *p, struct OneSlice *pRef);
  609. static void Slicer_computeTopAndBottom(Slicer *p);
  610. static int Slicer_getDeck(
  611. Tcl_Interp *interp, /* Put error messages here */
  612. Slicer *p, /* The slicer */
  613. double rX, /* X coord used to find deck if pObj is a Z coord */
  614. Tcl_Obj *pObj, /* Either a deck name or a Z coordinate */
  615. struct OneSlice **ppS /* Write the slice pointer here */
  616. );
  617. static int Slicer_getDeckId(
  618. Tcl_Interp *interp, /* Put error messages here */
  619. Slicer *p, /* The slicer */
  620. Tcl_Obj *pObj, /* Either a deck name or a Z coordinate */
  621. struct OneSlice **ppS /* Write the slice pointer here */
  622. );
  623. static inline struct OneSlice *Slicer_getDeck_FromInt(
  624. Slicer *p,
  625. int did
  626. );
  627. static int slicer_drawline_do(
  628. Tcl_Interp *interp,
  629. Slicer *p,
  630. int coord_count,
  631. int *deckCoord,double *xCoord,double *yCoord,
  632. struct OneSlice **apDeck,
  633. Tcl_Obj *canvas,
  634. const char *zKTag,
  635. const char *zXTag,
  636. const char *zBTag
  637. );
  638. static inline double Slicer_Location_zabs(Slicer *p,struct OneSlice *pS,double x0,double dheight);
  639. static inline double Location_zdeck(Slicer *p,struct OneSlice *pS,double x0,double dheight);
  640. static int OOMethod_Slicer_drawline(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  641. static int OOMethod_Slicer_above(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  642. static int OOMethod_Slicer_below(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  643. static int OOMethod_Slicer_deckid_to_name(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  644. static int OOMethod_Slicer_deckname_to_id(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  645. static int OOMethod_Slicer_bbox_to_location(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  646. static int OOMethod_Slicer_bbox_to_midpoint(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  647. static int OOMethod_Slicer_xyz_to_location(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  648. static int OOMethod_Slicer_location_to_xyz(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  649. static int OOMethod_Slicer_location_z(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  650. static int OOMethod_Slicer_distance(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  651. static int OOMethod_Slicer_actualcoords(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  652. static int OOMethod_Slicer_canvascoords(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  653. static int OOMethod_Slicer_create(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  654. static int OOMethod_Slicer_deck_at_xyz(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  655. static int OOMethod_Slicer_deckid_at_xyx(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  656. static int OOMethod_Slicer_delete(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  657. static int OOMethod_Slicer_makedlist(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  658. static int OOMethod_Slicer_find(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  659. static int OOMethod_Slicer_finddid(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  660. static int OOMethod_Slicer_flatheight(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  661. static int OOMethod_Slicer_headroom(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  662. static int OOMethod_Slicer_ceiling(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  663. static int OOMethod_Slicer_height(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  664. static int OOMethod_Slicer_deckheight(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  665. static int OOMethod_Slicer_info(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  666. static int OOMethod_Slicer_list(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  667. static int OOMethod_Slicer_profile(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  668. static int OOMethod_Slicer_xoffset(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  669. static int OOMethod_Slicer_zoom(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  670. static int OOMethod_Slicer_upper_height(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  671. static int OOMethod_Slicer_Slicer_Init(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  672. static int Slicer_OO_Init(Tcl_Interp *interp);
  673. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/slicer.tcl generate-cfile-header */
  674. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/wallset.tcl generate-cfile-header */
  675. static void Wallset_Delete(ClientData clientData);
  676. static int Wallset_Clone(
  677. Tcl_Interp* interp, /* Tcl interpreter for error reporting */
  678. ClientData metadata, /* Metadata to be cloned */
  679. ClientData* newMetaData /* Where to put the cloned metadata */
  680. );
  681. static int OOMethod_Wallset_atvertex(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  682. static int OOMethod_Wallset_boundary(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  683. static int OOMethod_Wallset_closure(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  684. static int OOMethod_Wallset_closure_polygon(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  685. static int OOMethod_Wallset_closure_check(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  686. static int OOMethod_Wallset_comptlist(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  687. static int OOMethod_Wallset_corners(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  688. static int OOMethod_Wallset_delete(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  689. static int OOMethod_Wallset_firstboundary(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  690. static int OOMethod_Wallset_foreach(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  691. static int OOMethod_Wallset_info(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  692. static int OOMethod_Wallset_rawinfo(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  693. static int OOMethod_Wallset_insert(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  694. static int OOMethod_Wallset_primary(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  695. static int OOMethod_Wallset_intersect(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  696. static int OOMethod_Wallset_left(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  697. static int OOMethod_Wallset_list(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  698. static int OOMethod_Wallset_looseends(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  699. static int OOMethod_Wallset_nearest(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  700. static int OOMethod_Wallset_nextcwwall(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  701. static int OOMethod_Wallset_right(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  702. static int OOMethod_Wallset_selfcheck(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  703. static int OOMethod_Wallset_zoom(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  704. static int OOMethod_Wallset_constructor(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  705. static int Wallset_OO_Init(Tcl_Interp *interp);
  706. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/wallset.tcl generate-cfile-header */
  707. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/faceset.tcl generate-cfile-header */
  708. static PolygonHullVertex *PolygonHullVertex_ById(PolygonHull *pHull, int id);
  709. static PolygonHullVertex *PolygonHullVertex_ByCoords(PolygonHull *pHull, VectorXYZ A);
  710. static PolygonHullVertex *PolygonHullVertex_Create(
  711. PolygonHull *pHull,
  712. int id,
  713. VectorXYZ point
  714. );
  715. static void PolygonHullVertex_Remove(PolygonHullVertex *pVertex);
  716. static const char *PolygonHullFace_VertexInject(PolygonHullFace *pFace,PolygonHullVertex *pThisVertex);
  717. static PolygonHullFace *PolygonHullFace_Create(
  718. PolygonHull *pHull,
  719. int id
  720. );
  721. static PolygonHullFace *PolygonHull_mergeFaceList(PolygonHullFace *a, PolygonHullFace *b);
  722. static PolygonHullFace *PolygonHull_sortFaceList(PolygonHullFace *pList);
  723. static PolygonHullFace *PolygonHullFace_ById(PolygonHull *pHull, int id);
  724. static int PolygonHull_findFace(
  725. Tcl_Interp *interp, /* Leave any error message here */
  726. PolygonHull *pHull,
  727. Tcl_Obj *pObj, /* The PolygonHullFace ID */
  728. PolygonHullFace **ppHullFace /* Write PolygonHullFace pointer here */
  729. );
  730. static void PolygonHullFace_Remove(PolygonHullFace *pFace);
  731. static void PolygonHullFace_SerializeEdges(PolygonHullFace *p);
  732. static void PolygonHullFace_Compute(PolygonHullFace *pFace);
  733. static double PolygonHull_sqrDistPointToEdge(
  734. VectorXYZ A, VectorXYZ B, /* End points of the line segment */
  735. VectorXYZ X /* The point to measure distance to */
  736. );
  737. static double PolygonHull_intersectLineSegFace(
  738. PolygonHullFace *pFace, /* The triangle we are trying to intersect */
  739. VectorXYZ pStart, /* Start of the line segment */
  740. VectorXYZ pEnd, /* End of the line segment */
  741. VectorXYZ pIntersect /* Point of intersection written here if not NULL */
  742. );
  743. static PolygonHullFace *PolygonHullFace_findHits(PolygonHull *pHull, VectorXYZ A, VectorXYZ B);
  744. static double PolygonHull_closestPointOnFace(PolygonHullFace *p, VectorXYZ X, VectorXYZ R);
  745. static PolygonHullFace *PolygonHullFace_findClosest(PolygonHull *pHull,VectorXYZ X, VectorXYZ R, double *pDist);
  746. static PolygonHullVolume *PolygonHullVolume_ById(PolygonHull *pHull, int id);
  747. static PolygonHullVolume *PolygonHullVolume_Create(
  748. PolygonHull *pHull,
  749. int id
  750. );
  751. static void PolygonHullVolume_Unlink(PolygonHullVolume *pVolume);
  752. static void PolygonHull_clearSurfaces(PolygonHull *pHull);
  753. static void PolygonHull_Reset(PolygonHull *pHull);
  754. static void PolygonHull_Delete(ClientData clientData);
  755. static int PolygonHull_Clone(
  756. Tcl_Interp* interp, /* Tcl interpreter for error reporting */
  757. ClientData metadata, /* Metadata to be cloned */
  758. ClientData* newMetaData /* Where to put the cloned metadata */
  759. );
  760. static int OOMethod_PolygonHull_vertex_create(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  761. static int OOMethod_PolygonHull_vertex_coords(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  762. static int OOMethod_PolygonHull_vertex_delete(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  763. static int OOMethod_PolygonHull_vertex_idlist(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  764. static int OOMethod_PolygonHull_vertex_inject(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  765. static int OOMethod_PolygonHull_vertex_list(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  766. static int OOMethod_PolygonHull_vertex_at(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  767. static int OOMethod_PolygonHull_face_info(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  768. static int OOMethod_PolygonHull_face_exists(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  769. static int OOMethod_PolygonHull_face_active(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  770. static int OOMethod_PolygonHull_face_center(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  771. static int OOMethod_PolygonHull_face_polygon(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  772. static int OOMethod_PolygonHull_face_vertices(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  773. static int OOMethod_PolygonHull_face_create(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  774. static int OOMethod_PolygonHull_face_delete(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  775. static int OOMethod_PolygonHull_face_intersect(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  776. static int OOMethod_PolygonHull_face_list(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  777. static int OOMethod_PolygonHull_face_nearest(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  778. static int OOMethod_PolygonHull_face_radius(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  779. static int OOMethod_PolygonHull_face_normal(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  780. static int OOMethod_PolygonHull_face_side(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  781. static int OOMethod_PolygonHull_face_volume(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  782. static int OOMethod_PolygonHull_faces_at(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  783. static int OOMethod_PolygonHull_face_within(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  784. static int OOMethod_PolygonHull_volume_create(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  785. static int OOMethod_PolygonHull_volume_delete(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  786. static int OOMethod_PolygonHull_volume_list(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  787. static int OOMethod_PolygonHull_volume_faces(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  788. static int OOMethod_PolygonHull_volume_group(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  789. static int OOMethod_PolygonHull_volume_center(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  790. static int OOMethod_PolygonHull_reset(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  791. static int OOMethod_PolygonHull_PolygonHull_Init(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  792. static int PolygonHull_OO_Init(Tcl_Interp *interp);
  793. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/faceset.tcl generate-cfile-header */
  794. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/geometry/module.ini generate-cfile-header */
  795. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/listcmd/listcmd.tcl generate-cfile-header */
  796. static int TclCmd_get(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  797. static int TclCmd_list_to_int(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  798. static int TclCmd_ladd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  799. static int TclCmd_ldelete(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  800. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/listcmd/listcmd.tcl generate-cfile-header */
  801. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/logicset/logicset.tcl generate-cfile-header */
  802. #define UCHAR(c) ((unsigned char) (c))
  803. #define TclFormatInt(buf, n) sprintf((buf), "%ld", (long)(n))
  804.  
  805. #define MEM_DEBUG 0
  806.  
  807. /*
  808. * Macros used to cast between pointers and integers (e.g. when storing an int
  809. * in ClientData), on 64-bit architectures they avoid gcc warning about "cast
  810. * to/from pointer from/to integer of different size".
  811. */
  812.  
  813. #if !defined(INT2PTR) && !defined(PTR2INT)
  814. # if defined(HAVE_INTPTR_T) || defined(intptr_t)
  815. # define INT2PTR(p) ((void *)(intptr_t)(p))
  816. # define PTR2INT(p) ((int)(intptr_t)(p))
  817. # else
  818. # define INT2PTR(p) ((void *)(p))
  819. # define PTR2INT(p) ((int)(p))
  820. # endif
  821. #endif
  822. #if !defined(UINT2PTR) && !defined(PTR2UINT)
  823. # if defined(HAVE_UINTPTR_T) || defined(uintptr_t)
  824. # define UINT2PTR(p) ((void *)(uintptr_t)(p))
  825. # define PTR2UINT(p) ((unsigned int)(uintptr_t)(p))
  826. # else
  827. # define UINT2PTR(p) ((void *)(p))
  828. # define PTR2UINT(p) ((unsigned int)(p))
  829. # endif
  830. #endif
  831.  
  832. #define VERSION "1.0"
  833.  
  834. /*
  835. ** Internal call required for munging integers
  836. */
  837. #ifndef _TCLINT
  838. /*
  839. * The structure used as the internal representation of Tcl list objects. This
  840. * struct is grown (reallocated and copied) as necessary to hold all the
  841. * list's element pointers. The struct might contain more slots than currently
  842. * used to hold all element pointers. This is done to make append operations
  843. * faster.
  844. *
  845. * We only need this when compiling as a seperate library from tcl
  846. */
  847.  
  848. typedef struct List {
  849. int refCount;
  850. int maxElemCount; /* Total number of element array slots. */
  851. int elemCount; /* Current number of list elements. */
  852. int canonicalFlag; /* Set if the string representation was
  853. * derived from the list representation. May
  854. * be ignored if there is no string rep at
  855. * all.*/
  856. Tcl_Obj *elements; /* First list element; the struct is grown to
  857. * accomodate all elements. */
  858. } List;
  859. #endif
  860. /*
  861. * During execution of the "lsort" command, structures of the following type
  862. * are used to arrange the objects being sorted into a collection of linked
  863. * lists.
  864. */
  865.  
  866. typedef struct SortElement {
  867. union {
  868. char *strValuePtr;
  869. long intValue;
  870. double doubleValue;
  871. Tcl_Obj *objValuePtr;
  872. } index;
  873. Tcl_Obj *objPtr; /* Object being sorted, or its index. */
  874. struct SortElement *nextPtr;/* Next element in the list, or NULL for end
  875. * of list. */
  876. } SortElement;
  877.  
  878.  
  879. typedef struct SortInfo {
  880. int isIncreasing; /* Nonzero means sort in increasing order. */
  881. int sortMode; /* The sort mode. One of SORTMODE_* values * defined below. */
  882. Tcl_Obj *compareCmdPtr; /* The Tcl comparison command when sortMode is
  883. * SORTMODE_COMMAND. Pre-initialized to hold
  884. * base of command. */
  885. int *indexv; /* If the -index option was specified, this
  886. * holds the indexes contained in the list
  887. *
  888. * supplied as an argument to that option.
  889. * NULL if no indexes supplied, and points to
  890. * singleIndex field when only one
  891. * supplied.
  892. */
  893. int indexc; /* Number of indexes in indexv array. */
  894. int singleIndex; /* Static space for common index case. */
  895. int unique;
  896. int numElements;
  897. Tcl_Interp *interp; /* The interpreter in which the sort is being
  898. * done.
  899. */
  900. int resultCode; /* Completion code for the lsort command. If
  901. * an error occurs during the sort this is
  902. * changed from TCL_OK to TCL_ERROR. */
  903. } SortInfo;
  904.  
  905. /*
  906. * These function pointer types are used with the "lsearch" and "lsort"
  907. * commands to facilitate the "-nocase" option.
  908. */
  909.  
  910. typedef int (*SortStrCmpFn_t) (const char *, const char *);
  911. typedef int (*SortMemCmpFn_t) (const void *, const void *, size_t);
  912.  
  913. /*
  914. * The "lsort" command needs to pass certain information down to the function
  915. * that compares two list elements, and the comparison function needs to pass
  916. * success or failure information back up to the top-level "lsort" command.
  917. * The following structure is used to pass this information.
  918. */
  919.  
  920.  
  921. /*
  922. * The "sortMode" field of the SortInfo structure can take on any of the
  923. * following values.
  924. */
  925.  
  926. #define SORTMODE_ASCII 0
  927. #define SORTMODE_INTEGER 1
  928. #define SORTMODE_REAL 2
  929. #define SORTMODE_COMMAND 3
  930. #define SORTMODE_DICTIONARY 4
  931. #define SORTMODE_ASCII_NC 8
  932.  
  933. /*
  934. * Magic values for the index field of the SortInfo structure. Note that the
  935. * index "end-1" will be translated to SORTIDX_END-1, etc.
  936. */
  937.  
  938. #define SORTIDX_NONE -1 /* Not indexed; use whole value. */
  939. #define SORTIDX_END -2 /* Indexed from end. */
  940.  
  941. /*
  942. * Forward declarations for procedures defined in this file:
  943. */
  944.  
  945. static int DictionaryCompare(char *left, char *right);
  946. static SortElement * MergeLists(SortElement *leftPtr, SortElement *rightPtr,
  947. SortInfo *infoPtr);
  948. static int SortCompare(SortElement *firstPtr, SortElement *second,
  949. SortInfo *infoPtr);
  950. static Tcl_Obj *Odie_MergeList_ToObj(SortElement *elementPtr);
  951. static int TclCmd_logicset_union(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  952. static int TclCmd_logicset_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  953. static int TclCmd_logicset_contains(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  954. static int TclCmd_logicset_empty(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  955. static int TclCmd_logicset_expr_and(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  956. static int TclCmd_logicset_expr_or(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  957. static int TclCmd_logicset_product_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  958. static int TclCmd_logicset_product_union(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  959. static int TclCmd_logicset_product_xor(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  960. static int TclCmd_logicset_product_missing(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  961. static int TclCmd_logicset_remove(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  962. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/logicset/logicset.tcl generate-cfile-header */
  963. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/literal/literal.tcl generate-cfile-header */
  964. /*
  965. ** constant.c
  966. ** Series of routines to minimize memory usage through the use
  967. ** of shared strings
  968. */
  969.  
  970. static Tcl_HashTable OdieLiteralStringTable;
  971. static Tcl_Obj *OdieStatic[14];
  972. static unsigned int nOdieObjString = 0;
  973. static unsigned int nOdieHashTable = 0;
  974. static unsigned int nOdieHashTableCreated = 0;
  975. static unsigned int nOdieHashTableDeleted = 0;
  976. static unsigned int nOdieDictSpecCount = 0;
  977. static unsigned int nOdieDictSpecCreated = 0;
  978. static unsigned int nOdieDictSpecDeleted = 0;
  979. static unsigned int nOdieDictSpecShared = 0;
  980. static unsigned int nOdieDictSpecNull = 0;
  981. static unsigned int nOdieDictSpecRecycled = 0;
  982. static unsigned int nOdieDictSpecModified = 0;
  983. static unsigned int nOdieDictSpecAccessed = 0;
  984.  
  985. static int OdieTrace=0;
  986.  
  987. typedef struct constObj {
  988. char *string;
  989. Tcl_Obj *tclobj;
  990. } constObj;
  991. static Tcl_Obj *Odie_constant(const char *zName,int create);
  992. static void Odie_constant_inject(Tcl_Obj *value);
  993. static int TclCmd_literal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  994. static int TclCmd_literal_dump(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  995. static int TclCmd_literal_stats(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  996. static int TclCmd_constant_string(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  997. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/literal/literal.tcl generate-cfile-header */
  998. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/module.ini generate-cfile-header */
  999. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/param.tcl generate-cfile-header */
  1000. Tcl_Interp *local_interp = NULL;
  1001. Simulator *CurrentSim = NULL;
  1002. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/param.tcl generate-cfile-header */
  1003. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/location.tcl generate-cfile-header */
  1004. static int TclCmd_location_grid_square(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  1005. static int TclCmd_location_gridhash_square(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  1006. static int TclCmd_location_location_gridhash(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  1007. static int TclCmd_location_grid_hex(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  1008. static int TclCmd_location_gridhash_hex(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  1009. static int TclCmd_location_gridhash_adjacent(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  1010. static int TclCmd_location_object(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  1011. static int TclCmd_location_midpoint(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  1012. static int TclCmd_location_match(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
  1013. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/location.tcl generate-cfile-header */
  1014. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/simulator.tcl generate-cfile-header */
  1015. static int OOMethod_Simulator_C_Init(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1016. static int Simulator_OO_Init(Tcl_Interp *interp);
  1017. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/simulator.tcl generate-cfile-header */
  1018. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/entity.tcl generate-cfile-header */
  1019. #define CSTRUCT_agent 1
  1020. #define CSTRUCT_compartment 2
  1021. #define CSTRUCT_crew 3
  1022. #define CSTRUCT_entity 4
  1023. #define CSTRUCT_objective 5
  1024. #define CSTRUCT_portal 6
  1025. #define CSTRUCT_routecompartment 7
  1026. #define CSTRUCT_routeportal 8
  1027. #define CSTRUCT_simlink 9
  1028. #define CSTRUCT_simnode 10
  1029. #define CSTRUCT_simulator 11
  1030. #define CSTRUCT_Count 11
  1031. #define CSTRUCT_ENTITY_AliasCount 19
  1032.  
  1033. #define ENTITY_ACTIVE_NULL 0 /* Not Checked */
  1034. #define ENTITY_ACTIVE_SHOW 1 /* Mark Checked */
  1035. #define ENTITY_ACTIVE_HIDE 2 /* Marked Hidden */
  1036. #define ENTITY_CLASS_AGENT a /* Agent */
  1037. #define ENTITY_CLASS_COMPARTMENT c /* Compartment */
  1038. #define ENTITY_CLASS_EQUIPMENT e /* Equipment */
  1039. #define ENTITY_CLASS_LINK l /* Conduit, Cable or Link */
  1040. #define ENTITY_CLASS_MATERIAL m /* Material */
  1041. #define ENTITY_CLASS_PORTAL p /* Portal */
  1042. #define ENTITY_CLASS_ROLLUP r /* Deactivation Rollup */
  1043. #define ENTITY_CLASS_HUMAN v /* Human */
  1044. #define ENTITY_CLASS_WALL w /* Wall Type */
  1045. #define ENTITY_CLASS_TREE x /* Type Tree Branch */
  1046. #define ENTITY_CLASS_GENERIC y /* Generic Type */
  1047. #define CSTRUCT_ENTITY_ACTIVE 0
  1048. #define CSTRUCT_ENTITY_CHANGED 1
  1049. #define CSTRUCT_ENTITY_CLASS 2
  1050. #define CSTRUCT_ENTITY_DRAWN 3
  1051. #define CSTRUCT_ENTITY_GROUPID 4
  1052. #define CSTRUCT_ENTITY_HIDDEN 5
  1053. #define CSTRUCT_ENTITY_HIGHLIGHT 6
  1054. #define CSTRUCT_ENTITY_IS_TYPE 7
  1055. #define CSTRUCT_ENTITY_MOVED 8
  1056. #define CSTRUCT_ENTITY_NCHILD 9
  1057. #define CSTRUCT_ENTITY_ONCOUNT 10
  1058. #define CSTRUCT_ENTITY_OPEN 11
  1059. #define CSTRUCT_ENTITY_PARENT 12
  1060. #define CSTRUCT_ENTITY_REDRAW 13
  1061. #define CSTRUCT_ENTITY_REPAINT 14
  1062. #define CSTRUCT_ENTITY_SYNTHETIC 15
  1063. #define CSTRUCT_ENTITY_TRACE 16
  1064. #define CSTRUCT_ENTITY_VISIBLE 17
  1065. #define CSTRUCT_ENTITY_Count 18
  1066. static int OOMethod_OOEntity_C_Init(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1067. static int OOMethod_OOEntity_create(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1068. static int OOMethod_OOEntity_attach_to(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1069. static int OOMethod_OOEntity_compartment(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1070. static int OOMethod_OOEntity_comptid(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1071. static int OOMethod_OOEntity_count(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1072. static int OOMethod_OOEntity_deckid(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1073. static int OOMethod_OOEntity_delete(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1074. static int OOMethod_OOEntity_drawn_reset(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1075. static int OOMethod_OOEntity_exists(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1076. static int OOMethod_OOEntity_for(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1077. static int OOMethod_OOEntity_foreach(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1078. static int OOMethod_OOEntity_groupid(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1079. static int OOMethod_OOEntity_groups_recalculate(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1080. static int OOMethod_OOEntity_hidden_inherit(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1081. static int OOMethod_OOEntity_list(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1082. static int OOMethod_OOEntity_location(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1083. static int OOMethod_OOEntity_midpoint(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1084. static int OOMethod_OOEntity_nodeget(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1085. static int OOMethod_OOEntity_nodeput(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1086. static int OOMethod_OOEntity_nodewith(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1087. static int OOMethod_OOEntity_normalize(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1088. static int OOMethod_OOEntity_orientation(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1089. static int OOMethod_OOEntity_redraw(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1090. static int OOMethod_OOEntity_reset(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1091. static int OOMethod_OOEntity_setting(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1092. static int OOMethod_OOEntity_spec_get(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1093. static int OOMethod_OOEntity_spec_put(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1094. static int OOMethod_OOEntity_spec_replace(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1095. static int OOMethod_OOEntity_struct_get(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1096. static int OOMethod_OOEntity_struct_put(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1097. static int OOMethod_OOEntity_type(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1098. static int OOMethod_OOEntity_typeid(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1099. static int OOMethod_OOEntity_visible(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1100. static int OOMethod_OOEntity_visible_filter(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1101. static int OOMethod_OOEntity_visible_hidden_subtract(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1102. static int OOMethod_OOEntity_visible_inherit(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1103. static int OOMethod_OOEntity_visible_reset(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1104. static int OOMethod_OOEntity_visible_tree(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1105. static int OOMethod_OOEntity_witheach(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1106. static int OOEntity_OO_Init(Tcl_Interp *interp);
  1107. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/entity.tcl generate-cfile-header */
  1108. /* BEGIN /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/simtype.tcl generate-cfile-header */
  1109. static int OOMethod_SimType_C_Init(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1110. static int OOMethod_SimType_children(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1111. static int OOMethod_SimType_count(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1112. static int OOMethod_SimType_create(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1113. static int OOMethod_SimType_delete(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1114. static int OOMethod_SimType_exists(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1115. static int OOMethod_SimType_for(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1116. static int OOMethod_SimType_foreach(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1117. static int OOMethod_SimType_groupid(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1118. static int OOMethod_SimType_list(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1119. static int OOMethod_SimType_nodeget(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1120. static int OOMethod_SimType_nodeput(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1121. static int OOMethod_SimType_nodewith(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1122. static int OOMethod_SimType_normalize(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1123. static int OOMethod_SimType_parent(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1124. static int OOMethod_SimType_setting(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1125. static int OOMethod_SimType_spec_get(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1126. static int OOMethod_SimType_spec_put(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1127. static int OOMethod_SimType_spec_replace(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1128. static int OOMethod_SimType_struct_get(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1129. static int OOMethod_SimType_struct_put(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1130. static int OOMethod_SimType_type(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1131. static int OOMethod_SimType_typeid(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1132. static int OOMethod_SimType_visible_reset(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1133. static int OOMethod_SimType_witheach(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext objectContext ,int objc ,Tcl_Obj *const *objv);
  1134. static int SimType_OO_Init(Tcl_Interp *interp);
  1135. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/simtype.tcl generate-cfile-header */
  1136. /* END /Users/seandeelywoods/build/odie/odielib/cmodules/typespec/module.ini generate-cfile-header */
  1137. /* END generate-cfile-header */
  1138. /* BEGIN generate-cfile-constant */
  1139. const static Tcl_ObjectMetadataType LinkDataType = {
  1140. TCL_OO_METADATA_VERSION_CURRENT,
  1141. "Link",
  1142. NULL,
  1143. NULL
  1144. };
  1145. #define GETLINK(OBJCONTEXT) (Link *) Tcl_ObjectGetMetadata(OBJCONTEXT,&LinkDataType)
  1146. const static Tcl_ObjectMetadataType HashDataType = {
  1147. TCL_OO_METADATA_VERSION_CURRENT,
  1148. "Hash",
  1149. NULL,
  1150. NULL
  1151. };
  1152. #define GETHASH(OBJCONTEXT) (Hash *) Tcl_ObjectGetMetadata(OBJCONTEXT,&HashDataType)
  1153. const static Tcl_ObjectMetadataType HashElemDataType = {
  1154. TCL_OO_METADATA_VERSION_CURRENT,
  1155. "HashElem",
  1156. NULL,
  1157. NULL
  1158. };
  1159. #define GETHASHELEM(OBJCONTEXT) (HashElem *) Tcl_ObjectGetMetadata(OBJCONTEXT,&HashElemDataType)
  1160. const static Tcl_ObjectMetadataType Odie_MatrixObjDataType = {
  1161. TCL_OO_METADATA_VERSION_CURRENT,
  1162. "Odie_MatrixObj",
  1163. NULL,
  1164. NULL
  1165. };
  1166. #define GETODIE_MATRIXOBJ(OBJCONTEXT) (Odie_MatrixObj *) Tcl_ObjectGetMetadata(OBJCONTEXT,&Odie_MatrixObjDataType)
  1167. const static Tcl_ObjectMetadataType MatrixFormDataType = {
  1168. TCL_OO_METADATA_VERSION_CURRENT,
  1169. "MatrixForm",
  1170. NULL,
  1171. NULL
  1172. };
  1173. #define GETMATRIXFORM(OBJCONTEXT) (MatrixForm *) Tcl_ObjectGetMetadata(OBJCONTEXT,&MatrixFormDataType)
  1174. const Tcl_ObjType matrix_tclobjtype = {
  1175. .name="matrix",
  1176. .freeIntRepProc = &MatrixObj_freeIntRepProc,
  1177. .dupIntRepProc = &MatrixObj_dupIntRepProc,
  1178. .updateStringProc = &MatrixObj_updateStringProc,
  1179. .setFromAnyProc = &MatrixObj_setFromAnyProc
  1180. };
  1181. const static Tcl_ObjectMetadataType TriagPointDataType = {
  1182. TCL_OO_METADATA_VERSION_CURRENT,
  1183. "TriagPoint",
  1184. NULL,
  1185. NULL
  1186. };
  1187. #define GETTRIAGPOINT(OBJCONTEXT) (TriagPoint *) Tcl_ObjectGetMetadata(OBJCONTEXT,&TriagPointDataType)
  1188. const static Tcl_ObjectMetadataType TriagSegmentDataType = {
  1189. TCL_OO_METADATA_VERSION_CURRENT,
  1190. "TriagSegment",
  1191. NULL,
  1192. NULL
  1193. };
  1194. #define GETTRIAGSEGMENT(OBJCONTEXT) (TriagSegment *) Tcl_ObjectGetMetadata(OBJCONTEXT,&TriagSegmentDataType)
  1195. const static Tcl_ObjectMetadataType TriagSegSetDataType = {
  1196. TCL_OO_METADATA_VERSION_CURRENT,
  1197. "TriagSegSet",
  1198. NULL,
  1199. NULL
  1200. };
  1201. #define GETTRIAGSEGSET(OBJCONTEXT) (TriagSegSet *) Tcl_ObjectGetMetadata(OBJCONTEXT,&TriagSegSetDataType)
  1202. const static Tcl_ObjectMetadataType Odie_PolygonDataType = {
  1203. TCL_OO_METADATA_VERSION_CURRENT,
  1204. "Odie_Polygon",
  1205. NULL,
  1206. NULL
  1207. };
  1208. #define GETODIE_POLYGON(OBJCONTEXT) (Odie_Polygon *) Tcl_ObjectGetMetadata(OBJCONTEXT,&Odie_PolygonDataType)
  1209. const Tcl_ObjType polygon_tclobjtype = {
  1210. .name="polygon",
  1211. .freeIntRepProc = &PolygonObj_freeIntRepProc,
  1212. .dupIntRepProc = &PolygonObj_dupIntRepProc,
  1213. .updateStringProc = &PolygonObj_updateStringRepProc,
  1214. .setFromAnyProc = &PolygonObj_setFromAnyProc
  1215. };
  1216. const static Tcl_ObjectMetadataType Odie_FaceXYZDataType = {
  1217. TCL_OO_METADATA_VERSION_CURRENT,
  1218. "Odie_FaceXYZ",
  1219. NULL,
  1220. NULL
  1221. };
  1222. #define GETODIE_FACEXYZ(OBJCONTEXT) (Odie_FaceXYZ *) Tcl_ObjectGetMetadata(OBJCONTEXT,&Odie_FaceXYZDataType)
  1223. const Tcl_ObjType odie_polygon_tclobjtype = {
  1224. .name="odie_polygon",
  1225. .freeIntRepProc = &Odie_FaceXYZ_freeIntRepProc,
  1226. .dupIntRepProc = &Odie_FaceXYZ_dupIntRepProc,
  1227. .updateStringProc = &Odie_FaceXYZ_updateStringProc,
  1228. .setFromAnyProc = &Odie_FaceXYZ_setFromAnyProc
  1229. };
  1230. const static Tcl_ObjectMetadataType FaceBoundaryDataType = {
  1231. TCL_OO_METADATA_VERSION_CURRENT,
  1232. "FaceBoundary",
  1233. NULL,
  1234. NULL
  1235. };
  1236. #define GETFACEBOUNDARY(OBJCONTEXT) (FaceBoundary *) Tcl_ObjectGetMetadata(OBJCONTEXT,&FaceBoundaryDataType)
  1237. const static Tcl_ObjectMetadataType SegmentDataType = {
  1238. TCL_OO_METADATA_VERSION_CURRENT,
  1239. "Segment",
  1240. NULL,
  1241. NULL
  1242. };
  1243. #define GETSEGMENT(OBJCONTEXT) (Segment *) Tcl_ObjectGetMetadata(OBJCONTEXT,&SegmentDataType)
  1244. const static Tcl_ObjectMetadataType SegmentSetDataType = {
  1245. TCL_OO_METADATA_VERSION_CURRENT,
  1246. "SegmentSet",
  1247. SegmentSet_Delete,
  1248. SegmentSet_Clone
  1249. };
  1250. #define GETSEGMENTSET(OBJCONTEXT) (SegmentSet *) Tcl_ObjectGetMetadata(OBJCONTEXT,&SegmentSetDataType)
  1251. const static Tcl_MethodType OOMethodType_SegmentSet_segment_info = {
  1252. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1253. .name = "segment_info",
  1254. .callProc = OOMethod_SegmentSet_segment_info,
  1255. .deleteProc = NULL,
  1256. .cloneProc = NULL
  1257. };
  1258. const static Tcl_MethodType OOMethodType_SegmentSet_SegmentSet_Init = {
  1259. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1260. .name = "SegmentSet_Init",
  1261. .callProc = OOMethod_SegmentSet_SegmentSet_Init,
  1262. .deleteProc = NULL,
  1263. .cloneProc = NULL
  1264. };
  1265. const static Tcl_MethodType OOMethodType_SegmentSet_modified = {
  1266. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1267. .name = "modified",
  1268. .callProc = OOMethod_SegmentSet_modified,
  1269. .deleteProc = NULL,
  1270. .cloneProc = NULL
  1271. };
  1272. const static Tcl_MethodType OOMethodType_SegmentSet_segment_count = {
  1273. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1274. .name = "segment_count",
  1275. .callProc = OOMethod_SegmentSet_segment_count,
  1276. .deleteProc = NULL,
  1277. .cloneProc = NULL
  1278. };
  1279. const static Tcl_MethodType OOMethodType_SegmentSet_bbox = {
  1280. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1281. .name = "bbox",
  1282. .callProc = OOMethod_SegmentSet_bbox,
  1283. .deleteProc = NULL,
  1284. .cloneProc = NULL
  1285. };
  1286. const static Tcl_MethodType OOMethodType_SegmentSet_segment_reset = {
  1287. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1288. .name = "segment_reset",
  1289. .callProc = OOMethod_SegmentSet_segment_reset,
  1290. .deleteProc = NULL,
  1291. .cloneProc = NULL
  1292. };
  1293. const static Tcl_MethodType OOMethodType_SegmentSet_segment_add = {
  1294. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1295. .name = "segment_add",
  1296. .callProc = OOMethod_SegmentSet_segment_add,
  1297. .deleteProc = NULL,
  1298. .cloneProc = NULL
  1299. };
  1300. const static Tcl_MethodType OOMethodType_SegmentSet_segment_add_virtual = {
  1301. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1302. .name = "segment_add_virtual",
  1303. .callProc = OOMethod_SegmentSet_segment_add_virtual,
  1304. .deleteProc = NULL,
  1305. .cloneProc = NULL
  1306. };
  1307. const static Tcl_MethodType OOMethodType_SegmentSet_polygon_add = {
  1308. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1309. .name = "polygon_add",
  1310. .callProc = OOMethod_SegmentSet_polygon_add,
  1311. .deleteProc = NULL,
  1312. .cloneProc = NULL
  1313. };
  1314. const static Tcl_MethodType OOMethodType_SegmentSet_vertex_add = {
  1315. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1316. .name = "vertex_add",
  1317. .callProc = OOMethod_SegmentSet_vertex_add,
  1318. .deleteProc = NULL,
  1319. .cloneProc = NULL
  1320. };
  1321. const static Tcl_MethodType OOMethodType_SegmentSet_segment_delete = {
  1322. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1323. .name = "segment_delete",
  1324. .callProc = OOMethod_SegmentSet_segment_delete,
  1325. .deleteProc = NULL,
  1326. .cloneProc = NULL
  1327. };
  1328. const static Tcl_MethodType OOMethodType_SegmentSet_delete = {
  1329. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1330. .name = "delete",
  1331. .callProc = OOMethod_SegmentSet_delete,
  1332. .deleteProc = NULL,
  1333. .cloneProc = NULL
  1334. };
  1335. const static Tcl_MethodType OOMethodType_SegmentSet_cleanup = {
  1336. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1337. .name = "cleanup",
  1338. .callProc = OOMethod_SegmentSet_cleanup,
  1339. .deleteProc = NULL,
  1340. .cloneProc = NULL
  1341. };
  1342. const static Tcl_MethodType OOMethodType_SegmentSet_cleanup_looseend = {
  1343. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1344. .name = "cleanup_looseend",
  1345. .callProc = OOMethod_SegmentSet_cleanup_looseend,
  1346. .deleteProc = NULL,
  1347. .cloneProc = NULL
  1348. };
  1349. const static Tcl_MethodType OOMethodType_SegmentSet_edge_connection = {
  1350. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1351. .name = "edge_connection",
  1352. .callProc = OOMethod_SegmentSet_edge_connection,
  1353. .deleteProc = NULL,
  1354. .cloneProc = NULL
  1355. };
  1356. const static Tcl_MethodType OOMethodType_SegmentSet_check_intersecting = {
  1357. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1358. .name = "check_intersecting",
  1359. .callProc = OOMethod_SegmentSet_check_intersecting,
  1360. .deleteProc = NULL,
  1361. .cloneProc = NULL
  1362. };
  1363. const static Tcl_MethodType OOMethodType_SegmentSet_check_coincident = {
  1364. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1365. .name = "check_coincident",
  1366. .callProc = OOMethod_SegmentSet_check_coincident,
  1367. .deleteProc = NULL,
  1368. .cloneProc = NULL
  1369. };
  1370. const static Tcl_MethodType OOMethodType_SegmentSet_segment_linelineintersect = {
  1371. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1372. .name = "segment_linelineintersect",
  1373. .callProc = OOMethod_SegmentSet_segment_linelineintersect,
  1374. .deleteProc = NULL,
  1375. .cloneProc = NULL
  1376. };
  1377. const static Tcl_MethodType OOMethodType_SegmentSet_segment_coincident = {
  1378. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1379. .name = "segment_coincident",
  1380. .callProc = OOMethod_SegmentSet_segment_coincident,
  1381. .deleteProc = NULL,
  1382. .cloneProc = NULL
  1383. };
  1384. const static Tcl_MethodType OOMethodType_SegmentSet_segment_find = {
  1385. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1386. .name = "segment_find",
  1387. .callProc = OOMethod_SegmentSet_segment_find,
  1388. .deleteProc = NULL,
  1389. .cloneProc = NULL
  1390. };
  1391. const static Tcl_MethodType OOMethodType_SegmentSet_vertex_delete = {
  1392. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1393. .name = "vertex_delete",
  1394. .callProc = OOMethod_SegmentSet_vertex_delete,
  1395. .deleteProc = NULL,
  1396. .cloneProc = NULL
  1397. };
  1398. const static Tcl_MethodType OOMethodType_SegmentSet_segment_next = {
  1399. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1400. .name = "segment_next",
  1401. .callProc = OOMethod_SegmentSet_segment_next,
  1402. .deleteProc = NULL,
  1403. .cloneProc = NULL
  1404. };
  1405. const static Tcl_MethodType OOMethodType_SegmentSet_check_oblique = {
  1406. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1407. .name = "check_oblique",
  1408. .callProc = OOMethod_SegmentSet_check_oblique,
  1409. .deleteProc = NULL,
  1410. .cloneProc = NULL
  1411. };
  1412. const static Tcl_MethodType OOMethodType_SegmentSet_check_looseends = {
  1413. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1414. .name = "check_looseends",
  1415. .callProc = OOMethod_SegmentSet_check_looseends,
  1416. .deleteProc = NULL,
  1417. .cloneProc = NULL
  1418. };
  1419. const static Tcl_MethodType OOMethodType_SegmentSet_fix_looseends = {
  1420. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1421. .name = "fix_looseends",
  1422. .callProc = OOMethod_SegmentSet_fix_looseends,
  1423. .deleteProc = NULL,
  1424. .cloneProc = NULL
  1425. };
  1426. const static Tcl_MethodType OOMethodType_SegmentSet_grid = {
  1427. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1428. .name = "grid",
  1429. .callProc = OOMethod_SegmentSet_grid,
  1430. .deleteProc = NULL,
  1431. .cloneProc = NULL
  1432. };
  1433. const static Tcl_MethodType OOMethodType_SegmentSet_segment_list = {
  1434. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1435. .name = "segment_list",
  1436. .callProc = OOMethod_SegmentSet_segment_list,
  1437. .deleteProc = NULL,
  1438. .cloneProc = NULL
  1439. };
  1440. const static Tcl_MethodType OOMethodType_SegmentSet_segment_coords = {
  1441. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1442. .name = "segment_coords",
  1443. .callProc = OOMethod_SegmentSet_segment_coords,
  1444. .deleteProc = NULL,
  1445. .cloneProc = NULL
  1446. };
  1447. const static Tcl_MethodType OOMethodType_SegmentSet_segment_uvcoords = {
  1448. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1449. .name = "segment_uvcoords",
  1450. .callProc = OOMethod_SegmentSet_segment_uvcoords,
  1451. .deleteProc = NULL,
  1452. .cloneProc = NULL
  1453. };
  1454. const static Tcl_MethodType OOMethodType_SegmentSet_selfcheck = {
  1455. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1456. .name = "selfcheck",
  1457. .callProc = OOMethod_SegmentSet_selfcheck,
  1458. .deleteProc = NULL,
  1459. .cloneProc = NULL
  1460. };
  1461. const static Tcl_MethodType OOMethodType_SegmentSet_uv_transform = {
  1462. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1463. .name = "uv_transform",
  1464. .callProc = OOMethod_SegmentSet_uv_transform,
  1465. .deleteProc = NULL,
  1466. .cloneProc = NULL
  1467. };
  1468. const static Tcl_MethodType OOMethodType_SegmentSet_polygons_xyz = {
  1469. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1470. .name = "polygons_xyz",
  1471. .callProc = OOMethod_SegmentSet_polygons_xyz,
  1472. .deleteProc = NULL,
  1473. .cloneProc = NULL
  1474. };
  1475. const static Tcl_MethodType OOMethodType_SegmentSet_polygons = {
  1476. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1477. .name = "polygons",
  1478. .callProc = OOMethod_SegmentSet_polygons,
  1479. .deleteProc = NULL,
  1480. .cloneProc = NULL
  1481. };
  1482. const static Tcl_MethodType OOMethodType_SegmentSet_polygon_faces = {
  1483. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1484. .name = "polygon_faces",
  1485. .callProc = OOMethod_SegmentSet_polygon_faces,
  1486. .deleteProc = NULL,
  1487. .cloneProc = NULL
  1488. };
  1489. const static Tcl_MethodType OOMethodType_SegmentSet_polygon_info = {
  1490. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1491. .name = "polygon_info",
  1492. .callProc = OOMethod_SegmentSet_polygon_info,
  1493. .deleteProc = NULL,
  1494. .cloneProc = NULL
  1495. };
  1496. const static Tcl_ObjectMetadataType PlotterDataType = {
  1497. TCL_OO_METADATA_VERSION_CURRENT,
  1498. "Plotter",
  1499. Plotter_Delete,
  1500. Plotter_Clone
  1501. };
  1502. #define GETPLOTTER(OBJCONTEXT) (Plotter *) Tcl_ObjectGetMetadata(OBJCONTEXT,&PlotterDataType)
  1503. const static Tcl_MethodType OOMethodType_Plotter_actualcoords = {
  1504. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1505. .name = "actualcoords",
  1506. .callProc = OOMethod_Plotter_actualcoords,
  1507. .deleteProc = NULL,
  1508. .cloneProc = NULL
  1509. };
  1510. const static Tcl_MethodType OOMethodType_Plotter_canvascoords = {
  1511. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1512. .name = "canvascoords",
  1513. .callProc = OOMethod_Plotter_canvascoords,
  1514. .deleteProc = NULL,
  1515. .cloneProc = NULL
  1516. };
  1517. const static Tcl_MethodType OOMethodType_Plotter_centerset = {
  1518. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1519. .name = "centerset",
  1520. .callProc = OOMethod_Plotter_centerset,
  1521. .deleteProc = NULL,
  1522. .cloneProc = NULL
  1523. };
  1524. const static Tcl_MethodType OOMethodType_Plotter_xoffset = {
  1525. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1526. .name = "xoffset",
  1527. .callProc = OOMethod_Plotter_xoffset,
  1528. .deleteProc = NULL,
  1529. .cloneProc = NULL
  1530. };
  1531. const static Tcl_MethodType OOMethodType_Plotter_yoffset = {
  1532. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1533. .name = "yoffset",
  1534. .callProc = OOMethod_Plotter_yoffset,
  1535. .deleteProc = NULL,
  1536. .cloneProc = NULL
  1537. };
  1538. const static Tcl_MethodType OOMethodType_Plotter_zoom = {
  1539. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1540. .name = "zoom",
  1541. .callProc = OOMethod_Plotter_zoom,
  1542. .deleteProc = NULL,
  1543. .cloneProc = NULL
  1544. };
  1545. const static Tcl_MethodType OOMethodType_Plotter_constructor = {
  1546. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1547. .name = "constructor",
  1548. .callProc = OOMethod_Plotter_constructor,
  1549. .deleteProc = NULL,
  1550. .cloneProc = NULL
  1551. };
  1552. const static Tcl_ObjectMetadataType OneSliceDataType = {
  1553. TCL_OO_METADATA_VERSION_CURRENT,
  1554. "OneSlice",
  1555. NULL,
  1556. NULL
  1557. };
  1558. #define GETONESLICE(OBJCONTEXT) (OneSlice *) Tcl_ObjectGetMetadata(OBJCONTEXT,&OneSliceDataType)
  1559. const static Tcl_ObjectMetadataType SlicerDataType = {
  1560. TCL_OO_METADATA_VERSION_CURRENT,
  1561. "Slicer",
  1562. Slicer_Delete,
  1563. Slicer_Clone
  1564. };
  1565. #define GETSLICER(OBJCONTEXT) (Slicer *) Tcl_ObjectGetMetadata(OBJCONTEXT,&SlicerDataType)
  1566. const static Tcl_MethodType OOMethodType_Slicer_drawline = {
  1567. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1568. .name = "drawline",
  1569. .callProc = OOMethod_Slicer_drawline,
  1570. .deleteProc = NULL,
  1571. .cloneProc = NULL
  1572. };
  1573. const static Tcl_MethodType OOMethodType_Slicer_above = {
  1574. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1575. .name = "above",
  1576. .callProc = OOMethod_Slicer_above,
  1577. .deleteProc = NULL,
  1578. .cloneProc = NULL
  1579. };
  1580. const static Tcl_MethodType OOMethodType_Slicer_below = {
  1581. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1582. .name = "below",
  1583. .callProc = OOMethod_Slicer_below,
  1584. .deleteProc = NULL,
  1585. .cloneProc = NULL
  1586. };
  1587. const static Tcl_MethodType OOMethodType_Slicer_deckid_to_name = {
  1588. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1589. .name = "deckid_to_name",
  1590. .callProc = OOMethod_Slicer_deckid_to_name,
  1591. .deleteProc = NULL,
  1592. .cloneProc = NULL
  1593. };
  1594. const static Tcl_MethodType OOMethodType_Slicer_deckname_to_id = {
  1595. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1596. .name = "deckname_to_id",
  1597. .callProc = OOMethod_Slicer_deckname_to_id,
  1598. .deleteProc = NULL,
  1599. .cloneProc = NULL
  1600. };
  1601. const static Tcl_MethodType OOMethodType_Slicer_bbox_to_location = {
  1602. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1603. .name = "bbox_to_location",
  1604. .callProc = OOMethod_Slicer_bbox_to_location,
  1605. .deleteProc = NULL,
  1606. .cloneProc = NULL
  1607. };
  1608. const static Tcl_MethodType OOMethodType_Slicer_bbox_to_midpoint = {
  1609. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1610. .name = "bbox_to_midpoint",
  1611. .callProc = OOMethod_Slicer_bbox_to_midpoint,
  1612. .deleteProc = NULL,
  1613. .cloneProc = NULL
  1614. };
  1615. const static Tcl_MethodType OOMethodType_Slicer_xyz_to_location = {
  1616. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1617. .name = "xyz_to_location",
  1618. .callProc = OOMethod_Slicer_xyz_to_location,
  1619. .deleteProc = NULL,
  1620. .cloneProc = NULL
  1621. };
  1622. const static Tcl_MethodType OOMethodType_Slicer_location_to_xyz = {
  1623. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1624. .name = "location_to_xyz",
  1625. .callProc = OOMethod_Slicer_location_to_xyz,
  1626. .deleteProc = NULL,
  1627. .cloneProc = NULL
  1628. };
  1629. const static Tcl_MethodType OOMethodType_Slicer_location_z = {
  1630. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1631. .name = "location_z",
  1632. .callProc = OOMethod_Slicer_location_z,
  1633. .deleteProc = NULL,
  1634. .cloneProc = NULL
  1635. };
  1636. const static Tcl_MethodType OOMethodType_Slicer_distance = {
  1637. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1638. .name = "distance",
  1639. .callProc = OOMethod_Slicer_distance,
  1640. .deleteProc = NULL,
  1641. .cloneProc = NULL
  1642. };
  1643. const static Tcl_MethodType OOMethodType_Slicer_actualcoords = {
  1644. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1645. .name = "actualcoords",
  1646. .callProc = OOMethod_Slicer_actualcoords,
  1647. .deleteProc = NULL,
  1648. .cloneProc = NULL
  1649. };
  1650. const static Tcl_MethodType OOMethodType_Slicer_canvascoords = {
  1651. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1652. .name = "canvascoords",
  1653. .callProc = OOMethod_Slicer_canvascoords,
  1654. .deleteProc = NULL,
  1655. .cloneProc = NULL
  1656. };
  1657. const static Tcl_MethodType OOMethodType_Slicer_create = {
  1658. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1659. .name = "create",
  1660. .callProc = OOMethod_Slicer_create,
  1661. .deleteProc = NULL,
  1662. .cloneProc = NULL
  1663. };
  1664. const static Tcl_MethodType OOMethodType_Slicer_deck_at_xyz = {
  1665. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1666. .name = "deck_at_xyz",
  1667. .callProc = OOMethod_Slicer_deck_at_xyz,
  1668. .deleteProc = NULL,
  1669. .cloneProc = NULL
  1670. };
  1671. const static Tcl_MethodType OOMethodType_Slicer_deckid_at_xyx = {
  1672. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1673. .name = "deckid_at_xyx",
  1674. .callProc = OOMethod_Slicer_deckid_at_xyx,
  1675. .deleteProc = NULL,
  1676. .cloneProc = NULL
  1677. };
  1678. const static Tcl_MethodType OOMethodType_Slicer_delete = {
  1679. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1680. .name = "delete",
  1681. .callProc = OOMethod_Slicer_delete,
  1682. .deleteProc = NULL,
  1683. .cloneProc = NULL
  1684. };
  1685. const static Tcl_MethodType OOMethodType_Slicer_makedlist = {
  1686. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1687. .name = "makedlist",
  1688. .callProc = OOMethod_Slicer_makedlist,
  1689. .deleteProc = NULL,
  1690. .cloneProc = NULL
  1691. };
  1692. const static Tcl_MethodType OOMethodType_Slicer_find = {
  1693. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1694. .name = "find",
  1695. .callProc = OOMethod_Slicer_find,
  1696. .deleteProc = NULL,
  1697. .cloneProc = NULL
  1698. };
  1699. const static Tcl_MethodType OOMethodType_Slicer_finddid = {
  1700. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1701. .name = "finddid",
  1702. .callProc = OOMethod_Slicer_finddid,
  1703. .deleteProc = NULL,
  1704. .cloneProc = NULL
  1705. };
  1706. const static Tcl_MethodType OOMethodType_Slicer_flatheight = {
  1707. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1708. .name = "flatheight",
  1709. .callProc = OOMethod_Slicer_flatheight,
  1710. .deleteProc = NULL,
  1711. .cloneProc = NULL
  1712. };
  1713. const static Tcl_MethodType OOMethodType_Slicer_headroom = {
  1714. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1715. .name = "headroom",
  1716. .callProc = OOMethod_Slicer_headroom,
  1717. .deleteProc = NULL,
  1718. .cloneProc = NULL
  1719. };
  1720. const static Tcl_MethodType OOMethodType_Slicer_ceiling = {
  1721. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1722. .name = "ceiling",
  1723. .callProc = OOMethod_Slicer_ceiling,
  1724. .deleteProc = NULL,
  1725. .cloneProc = NULL
  1726. };
  1727. const static Tcl_MethodType OOMethodType_Slicer_height = {
  1728. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1729. .name = "height",
  1730. .callProc = OOMethod_Slicer_height,
  1731. .deleteProc = NULL,
  1732. .cloneProc = NULL
  1733. };
  1734. const static Tcl_MethodType OOMethodType_Slicer_deckheight = {
  1735. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1736. .name = "deckheight",
  1737. .callProc = OOMethod_Slicer_deckheight,
  1738. .deleteProc = NULL,
  1739. .cloneProc = NULL
  1740. };
  1741. const static Tcl_MethodType OOMethodType_Slicer_info = {
  1742. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1743. .name = "info",
  1744. .callProc = OOMethod_Slicer_info,
  1745. .deleteProc = NULL,
  1746. .cloneProc = NULL
  1747. };
  1748. const static Tcl_MethodType OOMethodType_Slicer_list = {
  1749. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1750. .name = "list",
  1751. .callProc = OOMethod_Slicer_list,
  1752. .deleteProc = NULL,
  1753. .cloneProc = NULL
  1754. };
  1755. const static Tcl_MethodType OOMethodType_Slicer_profile = {
  1756. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1757. .name = "profile",
  1758. .callProc = OOMethod_Slicer_profile,
  1759. .deleteProc = NULL,
  1760. .cloneProc = NULL
  1761. };
  1762. const static Tcl_MethodType OOMethodType_Slicer_xoffset = {
  1763. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1764. .name = "xoffset",
  1765. .callProc = OOMethod_Slicer_xoffset,
  1766. .deleteProc = NULL,
  1767. .cloneProc = NULL
  1768. };
  1769. const static Tcl_MethodType OOMethodType_Slicer_zoom = {
  1770. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1771. .name = "zoom",
  1772. .callProc = OOMethod_Slicer_zoom,
  1773. .deleteProc = NULL,
  1774. .cloneProc = NULL
  1775. };
  1776. const static Tcl_MethodType OOMethodType_Slicer_upper_height = {
  1777. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1778. .name = "upper_height",
  1779. .callProc = OOMethod_Slicer_upper_height,
  1780. .deleteProc = NULL,
  1781. .cloneProc = NULL
  1782. };
  1783. const static Tcl_MethodType OOMethodType_Slicer_Slicer_Init = {
  1784. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1785. .name = "Slicer_Init",
  1786. .callProc = OOMethod_Slicer_Slicer_Init,
  1787. .deleteProc = NULL,
  1788. .cloneProc = NULL
  1789. };
  1790. const static Tcl_ObjectMetadataType BoundaryDataType = {
  1791. TCL_OO_METADATA_VERSION_CURRENT,
  1792. "Boundary",
  1793. NULL,
  1794. NULL
  1795. };
  1796. #define GETBOUNDARY(OBJCONTEXT) (Boundary *) Tcl_ObjectGetMetadata(OBJCONTEXT,&BoundaryDataType)
  1797. const static Tcl_ObjectMetadataType ComptBoxDataType = {
  1798. TCL_OO_METADATA_VERSION_CURRENT,
  1799. "ComptBox",
  1800. NULL,
  1801. NULL
  1802. };
  1803. #define GETCOMPTBOX(OBJCONTEXT) (ComptBox *) Tcl_ObjectGetMetadata(OBJCONTEXT,&ComptBoxDataType)
  1804. const static Tcl_ObjectMetadataType WallsetDataType = {
  1805. TCL_OO_METADATA_VERSION_CURRENT,
  1806. "Wallset",
  1807. Wallset_Delete,
  1808. Wallset_Clone
  1809. };
  1810. #define GETWALLSET(OBJCONTEXT) (Wallset *) Tcl_ObjectGetMetadata(OBJCONTEXT,&WallsetDataType)
  1811. const static Tcl_MethodType OOMethodType_Wallset_atvertex = {
  1812. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1813. .name = "atvertex",
  1814. .callProc = OOMethod_Wallset_atvertex,
  1815. .deleteProc = NULL,
  1816. .cloneProc = NULL
  1817. };
  1818. const static Tcl_MethodType OOMethodType_Wallset_boundary = {
  1819. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1820. .name = "boundary",
  1821. .callProc = OOMethod_Wallset_boundary,
  1822. .deleteProc = NULL,
  1823. .cloneProc = NULL
  1824. };
  1825. const static Tcl_MethodType OOMethodType_Wallset_closure = {
  1826. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1827. .name = "closure",
  1828. .callProc = OOMethod_Wallset_closure,
  1829. .deleteProc = NULL,
  1830. .cloneProc = NULL
  1831. };
  1832. const static Tcl_MethodType OOMethodType_Wallset_closure_polygon = {
  1833. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1834. .name = "closure_polygon",
  1835. .callProc = OOMethod_Wallset_closure_polygon,
  1836. .deleteProc = NULL,
  1837. .cloneProc = NULL
  1838. };
  1839. const static Tcl_MethodType OOMethodType_Wallset_closure_check = {
  1840. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1841. .name = "closure_check",
  1842. .callProc = OOMethod_Wallset_closure_check,
  1843. .deleteProc = NULL,
  1844. .cloneProc = NULL
  1845. };
  1846. const static Tcl_MethodType OOMethodType_Wallset_comptlist = {
  1847. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1848. .name = "comptlist",
  1849. .callProc = OOMethod_Wallset_comptlist,
  1850. .deleteProc = NULL,
  1851. .cloneProc = NULL
  1852. };
  1853. const static Tcl_MethodType OOMethodType_Wallset_corners = {
  1854. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1855. .name = "corners",
  1856. .callProc = OOMethod_Wallset_corners,
  1857. .deleteProc = NULL,
  1858. .cloneProc = NULL
  1859. };
  1860. const static Tcl_MethodType OOMethodType_Wallset_delete = {
  1861. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1862. .name = "delete",
  1863. .callProc = OOMethod_Wallset_delete,
  1864. .deleteProc = NULL,
  1865. .cloneProc = NULL
  1866. };
  1867. const static Tcl_MethodType OOMethodType_Wallset_firstboundary = {
  1868. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1869. .name = "firstboundary",
  1870. .callProc = OOMethod_Wallset_firstboundary,
  1871. .deleteProc = NULL,
  1872. .cloneProc = NULL
  1873. };
  1874. const static Tcl_MethodType OOMethodType_Wallset_foreach = {
  1875. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1876. .name = "foreach",
  1877. .callProc = OOMethod_Wallset_foreach,
  1878. .deleteProc = NULL,
  1879. .cloneProc = NULL
  1880. };
  1881. const static Tcl_MethodType OOMethodType_Wallset_info = {
  1882. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1883. .name = "info",
  1884. .callProc = OOMethod_Wallset_info,
  1885. .deleteProc = NULL,
  1886. .cloneProc = NULL
  1887. };
  1888. const static Tcl_MethodType OOMethodType_Wallset_rawinfo = {
  1889. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1890. .name = "rawinfo",
  1891. .callProc = OOMethod_Wallset_rawinfo,
  1892. .deleteProc = NULL,
  1893. .cloneProc = NULL
  1894. };
  1895. const static Tcl_MethodType OOMethodType_Wallset_insert = {
  1896. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1897. .name = "insert",
  1898. .callProc = OOMethod_Wallset_insert,
  1899. .deleteProc = NULL,
  1900. .cloneProc = NULL
  1901. };
  1902. const static Tcl_MethodType OOMethodType_Wallset_primary = {
  1903. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1904. .name = "primary",
  1905. .callProc = OOMethod_Wallset_primary,
  1906. .deleteProc = NULL,
  1907. .cloneProc = NULL
  1908. };
  1909. const static Tcl_MethodType OOMethodType_Wallset_intersect = {
  1910. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1911. .name = "intersect",
  1912. .callProc = OOMethod_Wallset_intersect,
  1913. .deleteProc = NULL,
  1914. .cloneProc = NULL
  1915. };
  1916. const static Tcl_MethodType OOMethodType_Wallset_left = {
  1917. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1918. .name = "left",
  1919. .callProc = OOMethod_Wallset_left,
  1920. .deleteProc = NULL,
  1921. .cloneProc = NULL
  1922. };
  1923. const static Tcl_MethodType OOMethodType_Wallset_list = {
  1924. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1925. .name = "list",
  1926. .callProc = OOMethod_Wallset_list,
  1927. .deleteProc = NULL,
  1928. .cloneProc = NULL
  1929. };
  1930. const static Tcl_MethodType OOMethodType_Wallset_looseends = {
  1931. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1932. .name = "looseends",
  1933. .callProc = OOMethod_Wallset_looseends,
  1934. .deleteProc = NULL,
  1935. .cloneProc = NULL
  1936. };
  1937. const static Tcl_MethodType OOMethodType_Wallset_nearest = {
  1938. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1939. .name = "nearest",
  1940. .callProc = OOMethod_Wallset_nearest,
  1941. .deleteProc = NULL,
  1942. .cloneProc = NULL
  1943. };
  1944. const static Tcl_MethodType OOMethodType_Wallset_nextcwwall = {
  1945. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1946. .name = "nextcwwall",
  1947. .callProc = OOMethod_Wallset_nextcwwall,
  1948. .deleteProc = NULL,
  1949. .cloneProc = NULL
  1950. };
  1951. const static Tcl_MethodType OOMethodType_Wallset_right = {
  1952. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1953. .name = "right",
  1954. .callProc = OOMethod_Wallset_right,
  1955. .deleteProc = NULL,
  1956. .cloneProc = NULL
  1957. };
  1958. const static Tcl_MethodType OOMethodType_Wallset_selfcheck = {
  1959. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1960. .name = "selfcheck",
  1961. .callProc = OOMethod_Wallset_selfcheck,
  1962. .deleteProc = NULL,
  1963. .cloneProc = NULL
  1964. };
  1965. const static Tcl_MethodType OOMethodType_Wallset_zoom = {
  1966. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1967. .name = "zoom",
  1968. .callProc = OOMethod_Wallset_zoom,
  1969. .deleteProc = NULL,
  1970. .cloneProc = NULL
  1971. };
  1972. const static Tcl_MethodType OOMethodType_Wallset_constructor = {
  1973. .version = TCL_OO_METADATA_VERSION_CURRENT,
  1974. .name = "constructor",
  1975. .callProc = OOMethod_Wallset_constructor,
  1976. .deleteProc = NULL,
  1977. .cloneProc = NULL
  1978. };
  1979. const static Tcl_ObjectMetadataType PolygonHullVertexDataType = {
  1980. TCL_OO_METADATA_VERSION_CURRENT,
  1981. "PolygonHullVertex",
  1982. NULL,
  1983. NULL
  1984. };
  1985. #define GETPOLYGONHULLVERTEX(OBJCONTEXT) (PolygonHullVertex *) Tcl_ObjectGetMetadata(OBJCONTEXT,&PolygonHullVertexDataType)
  1986. const static Tcl_ObjectMetadataType PolygonHullFaceDataType = {
  1987. TCL_OO_METADATA_VERSION_CURRENT,
  1988. "PolygonHullFace",
  1989. NULL,
  1990. NULL
  1991. };
  1992. #define GETPOLYGONHULLFACE(OBJCONTEXT) (PolygonHullFace *) Tcl_ObjectGetMetadata(OBJCONTEXT,&PolygonHullFaceDataType)
  1993. const static Tcl_ObjectMetadataType PolygonHullVolumeDataType = {
  1994. TCL_OO_METADATA_VERSION_CURRENT,
  1995. "PolygonHullVolume",
  1996. NULL,
  1997. NULL
  1998. };
  1999. #define GETPOLYGONHULLVOLUME(OBJCONTEXT) (PolygonHullVolume *) Tcl_ObjectGetMetadata(OBJCONTEXT,&PolygonHullVolumeDataType)
  2000. const static Tcl_ObjectMetadataType PolygonHullDataType = {
  2001. TCL_OO_METADATA_VERSION_CURRENT,
  2002. "PolygonHull",
  2003. PolygonHull_Delete,
  2004. PolygonHull_Clone
  2005. };
  2006. #define GETPOLYGONHULL(OBJCONTEXT) (PolygonHull *) Tcl_ObjectGetMetadata(OBJCONTEXT,&PolygonHullDataType)
  2007. const static Tcl_MethodType OOMethodType_PolygonHull_vertex_create = {
  2008. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2009. .name = "vertex_create",
  2010. .callProc = OOMethod_PolygonHull_vertex_create,
  2011. .deleteProc = NULL,
  2012. .cloneProc = NULL
  2013. };
  2014. const static Tcl_MethodType OOMethodType_PolygonHull_vertex_coords = {
  2015. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2016. .name = "vertex_coords",
  2017. .callProc = OOMethod_PolygonHull_vertex_coords,
  2018. .deleteProc = NULL,
  2019. .cloneProc = NULL
  2020. };
  2021. const static Tcl_MethodType OOMethodType_PolygonHull_vertex_delete = {
  2022. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2023. .name = "vertex_delete",
  2024. .callProc = OOMethod_PolygonHull_vertex_delete,
  2025. .deleteProc = NULL,
  2026. .cloneProc = NULL
  2027. };
  2028. const static Tcl_MethodType OOMethodType_PolygonHull_vertex_idlist = {
  2029. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2030. .name = "vertex_idlist",
  2031. .callProc = OOMethod_PolygonHull_vertex_idlist,
  2032. .deleteProc = NULL,
  2033. .cloneProc = NULL
  2034. };
  2035. const static Tcl_MethodType OOMethodType_PolygonHull_vertex_inject = {
  2036. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2037. .name = "vertex_inject",
  2038. .callProc = OOMethod_PolygonHull_vertex_inject,
  2039. .deleteProc = NULL,
  2040. .cloneProc = NULL
  2041. };
  2042. const static Tcl_MethodType OOMethodType_PolygonHull_vertex_list = {
  2043. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2044. .name = "vertex_list",
  2045. .callProc = OOMethod_PolygonHull_vertex_list,
  2046. .deleteProc = NULL,
  2047. .cloneProc = NULL
  2048. };
  2049. const static Tcl_MethodType OOMethodType_PolygonHull_vertex_at = {
  2050. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2051. .name = "vertex_at",
  2052. .callProc = OOMethod_PolygonHull_vertex_at,
  2053. .deleteProc = NULL,
  2054. .cloneProc = NULL
  2055. };
  2056. const static Tcl_MethodType OOMethodType_PolygonHull_face_info = {
  2057. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2058. .name = "face_info",
  2059. .callProc = OOMethod_PolygonHull_face_info,
  2060. .deleteProc = NULL,
  2061. .cloneProc = NULL
  2062. };
  2063. const static Tcl_MethodType OOMethodType_PolygonHull_face_exists = {
  2064. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2065. .name = "face_exists",
  2066. .callProc = OOMethod_PolygonHull_face_exists,
  2067. .deleteProc = NULL,
  2068. .cloneProc = NULL
  2069. };
  2070. const static Tcl_MethodType OOMethodType_PolygonHull_face_active = {
  2071. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2072. .name = "face_active",
  2073. .callProc = OOMethod_PolygonHull_face_active,
  2074. .deleteProc = NULL,
  2075. .cloneProc = NULL
  2076. };
  2077. const static Tcl_MethodType OOMethodType_PolygonHull_face_center = {
  2078. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2079. .name = "face_center",
  2080. .callProc = OOMethod_PolygonHull_face_center,
  2081. .deleteProc = NULL,
  2082. .cloneProc = NULL
  2083. };
  2084. const static Tcl_MethodType OOMethodType_PolygonHull_face_polygon = {
  2085. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2086. .name = "face_polygon",
  2087. .callProc = OOMethod_PolygonHull_face_polygon,
  2088. .deleteProc = NULL,
  2089. .cloneProc = NULL
  2090. };
  2091. const static Tcl_MethodType OOMethodType_PolygonHull_face_vertices = {
  2092. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2093. .name = "face_vertices",
  2094. .callProc = OOMethod_PolygonHull_face_vertices,
  2095. .deleteProc = NULL,
  2096. .cloneProc = NULL
  2097. };
  2098. const static Tcl_MethodType OOMethodType_PolygonHull_face_create = {
  2099. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2100. .name = "face_create",
  2101. .callProc = OOMethod_PolygonHull_face_create,
  2102. .deleteProc = NULL,
  2103. .cloneProc = NULL
  2104. };
  2105. const static Tcl_MethodType OOMethodType_PolygonHull_face_delete = {
  2106. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2107. .name = "face_delete",
  2108. .callProc = OOMethod_PolygonHull_face_delete,
  2109. .deleteProc = NULL,
  2110. .cloneProc = NULL
  2111. };
  2112. const static Tcl_MethodType OOMethodType_PolygonHull_face_intersect = {
  2113. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2114. .name = "face_intersect",
  2115. .callProc = OOMethod_PolygonHull_face_intersect,
  2116. .deleteProc = NULL,
  2117. .cloneProc = NULL
  2118. };
  2119. const static Tcl_MethodType OOMethodType_PolygonHull_face_list = {
  2120. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2121. .name = "face_list",
  2122. .callProc = OOMethod_PolygonHull_face_list,
  2123. .deleteProc = NULL,
  2124. .cloneProc = NULL
  2125. };
  2126. const static Tcl_MethodType OOMethodType_PolygonHull_face_nearest = {
  2127. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2128. .name = "face_nearest",
  2129. .callProc = OOMethod_PolygonHull_face_nearest,
  2130. .deleteProc = NULL,
  2131. .cloneProc = NULL
  2132. };
  2133. const static Tcl_MethodType OOMethodType_PolygonHull_face_radius = {
  2134. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2135. .name = "face_radius",
  2136. .callProc = OOMethod_PolygonHull_face_radius,
  2137. .deleteProc = NULL,
  2138. .cloneProc = NULL
  2139. };
  2140. const static Tcl_MethodType OOMethodType_PolygonHull_face_normal = {
  2141. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2142. .name = "face_normal",
  2143. .callProc = OOMethod_PolygonHull_face_normal,
  2144. .deleteProc = NULL,
  2145. .cloneProc = NULL
  2146. };
  2147. const static Tcl_MethodType OOMethodType_PolygonHull_face_side = {
  2148. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2149. .name = "face_side",
  2150. .callProc = OOMethod_PolygonHull_face_side,
  2151. .deleteProc = NULL,
  2152. .cloneProc = NULL
  2153. };
  2154. const static Tcl_MethodType OOMethodType_PolygonHull_face_volume = {
  2155. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2156. .name = "face_volume",
  2157. .callProc = OOMethod_PolygonHull_face_volume,
  2158. .deleteProc = NULL,
  2159. .cloneProc = NULL
  2160. };
  2161. const static Tcl_MethodType OOMethodType_PolygonHull_faces_at = {
  2162. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2163. .name = "faces_at",
  2164. .callProc = OOMethod_PolygonHull_faces_at,
  2165. .deleteProc = NULL,
  2166. .cloneProc = NULL
  2167. };
  2168. const static Tcl_MethodType OOMethodType_PolygonHull_face_within = {
  2169. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2170. .name = "face_within",
  2171. .callProc = OOMethod_PolygonHull_face_within,
  2172. .deleteProc = NULL,
  2173. .cloneProc = NULL
  2174. };
  2175. const static Tcl_MethodType OOMethodType_PolygonHull_volume_create = {
  2176. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2177. .name = "volume_create",
  2178. .callProc = OOMethod_PolygonHull_volume_create,
  2179. .deleteProc = NULL,
  2180. .cloneProc = NULL
  2181. };
  2182. const static Tcl_MethodType OOMethodType_PolygonHull_volume_delete = {
  2183. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2184. .name = "volume_delete",
  2185. .callProc = OOMethod_PolygonHull_volume_delete,
  2186. .deleteProc = NULL,
  2187. .cloneProc = NULL
  2188. };
  2189. const static Tcl_MethodType OOMethodType_PolygonHull_volume_list = {
  2190. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2191. .name = "volume_list",
  2192. .callProc = OOMethod_PolygonHull_volume_list,
  2193. .deleteProc = NULL,
  2194. .cloneProc = NULL
  2195. };
  2196. const static Tcl_MethodType OOMethodType_PolygonHull_volume_faces = {
  2197. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2198. .name = "volume_faces",
  2199. .callProc = OOMethod_PolygonHull_volume_faces,
  2200. .deleteProc = NULL,
  2201. .cloneProc = NULL
  2202. };
  2203. const static Tcl_MethodType OOMethodType_PolygonHull_volume_group = {
  2204. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2205. .name = "volume_group",
  2206. .callProc = OOMethod_PolygonHull_volume_group,
  2207. .deleteProc = NULL,
  2208. .cloneProc = NULL
  2209. };
  2210. const static Tcl_MethodType OOMethodType_PolygonHull_volume_center = {
  2211. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2212. .name = "volume_center",
  2213. .callProc = OOMethod_PolygonHull_volume_center,
  2214. .deleteProc = NULL,
  2215. .cloneProc = NULL
  2216. };
  2217. const static Tcl_MethodType OOMethodType_PolygonHull_reset = {
  2218. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2219. .name = "reset",
  2220. .callProc = OOMethod_PolygonHull_reset,
  2221. .deleteProc = NULL,
  2222. .cloneProc = NULL
  2223. };
  2224. const static Tcl_MethodType OOMethodType_PolygonHull_PolygonHull_Init = {
  2225. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2226. .name = "PolygonHull_Init",
  2227. .callProc = OOMethod_PolygonHull_PolygonHull_Init,
  2228. .deleteProc = NULL,
  2229. .cloneProc = NULL
  2230. };
  2231. const static Tcl_ObjectMetadataType Odie_ObjDataType = {
  2232. TCL_OO_METADATA_VERSION_CURRENT,
  2233. "Odie_Obj",
  2234. NULL,
  2235. NULL
  2236. };
  2237. #define GETODIE_OBJ(OBJCONTEXT) (Odie_Obj *) Tcl_ObjectGetMetadata(OBJCONTEXT,&Odie_ObjDataType)
  2238. const static Tcl_ObjectMetadataType entityObjDataType = {
  2239. TCL_OO_METADATA_VERSION_CURRENT,
  2240. "entityObj",
  2241. NULL,
  2242. NULL
  2243. };
  2244. #define GETENTITYOBJ(OBJCONTEXT) (entityObj *) Tcl_ObjectGetMetadata(OBJCONTEXT,&entityObjDataType)
  2245. const static Tcl_ObjectMetadataType OdieParamNameMapDataType = {
  2246. TCL_OO_METADATA_VERSION_CURRENT,
  2247. "OdieParamNameMap",
  2248. NULL,
  2249. NULL
  2250. };
  2251. #define GETODIEPARAMNAMEMAP(OBJCONTEXT) (OdieParamNameMap *) Tcl_ObjectGetMetadata(OBJCONTEXT,&OdieParamNameMapDataType)
  2252. const static Tcl_ObjectMetadataType Irm_LocationDataType = {
  2253. TCL_OO_METADATA_VERSION_CURRENT,
  2254. "Irm_Location",
  2255. NULL,
  2256. NULL
  2257. };
  2258. #define GETIRM_LOCATION(OBJCONTEXT) (Irm_Location *) Tcl_ObjectGetMetadata(OBJCONTEXT,&Irm_LocationDataType)
  2259. const static Tcl_ObjectMetadataType SimulatorDataType = {
  2260. TCL_OO_METADATA_VERSION_CURRENT,
  2261. "Simulator",
  2262. NULL,
  2263. NULL
  2264. };
  2265. #define GETSIMULATOR(OBJCONTEXT) (Simulator *) Tcl_ObjectGetMetadata(OBJCONTEXT,&SimulatorDataType)
  2266. const static Tcl_MethodType OOMethodType_Simulator_C_Init = {
  2267. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2268. .name = "C_Init",
  2269. .callProc = OOMethod_Simulator_C_Init,
  2270. .deleteProc = NULL,
  2271. .cloneProc = NULL
  2272. };
  2273. const static Tcl_ObjectMetadataType EntityDataType = {
  2274. TCL_OO_METADATA_VERSION_CURRENT,
  2275. "Entity",
  2276. NULL,
  2277. NULL
  2278. };
  2279. #define GETENTITY(OBJCONTEXT) (Entity *) Tcl_ObjectGetMetadata(OBJCONTEXT,&EntityDataType)
  2280. const static Tcl_MethodType OOMethodType_OOEntity_C_Init = {
  2281. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2282. .name = "C_Init",
  2283. .callProc = OOMethod_OOEntity_C_Init,
  2284. .deleteProc = NULL,
  2285. .cloneProc = NULL
  2286. };
  2287. const static Tcl_MethodType OOMethodType_OOEntity_create = {
  2288. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2289. .name = "create",
  2290. .callProc = OOMethod_OOEntity_create,
  2291. .deleteProc = NULL,
  2292. .cloneProc = NULL
  2293. };
  2294. const static Tcl_MethodType OOMethodType_OOEntity_attach_to = {
  2295. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2296. .name = "attach_to",
  2297. .callProc = OOMethod_OOEntity_attach_to,
  2298. .deleteProc = NULL,
  2299. .cloneProc = NULL
  2300. };
  2301. const static Tcl_MethodType OOMethodType_OOEntity_compartment = {
  2302. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2303. .name = "compartment",
  2304. .callProc = OOMethod_OOEntity_compartment,
  2305. .deleteProc = NULL,
  2306. .cloneProc = NULL
  2307. };
  2308. const static Tcl_MethodType OOMethodType_OOEntity_comptid = {
  2309. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2310. .name = "comptid",
  2311. .callProc = OOMethod_OOEntity_comptid,
  2312. .deleteProc = NULL,
  2313. .cloneProc = NULL
  2314. };
  2315. const static Tcl_MethodType OOMethodType_OOEntity_count = {
  2316. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2317. .name = "count",
  2318. .callProc = OOMethod_OOEntity_count,
  2319. .deleteProc = NULL,
  2320. .cloneProc = NULL
  2321. };
  2322. const static Tcl_MethodType OOMethodType_OOEntity_deckid = {
  2323. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2324. .name = "deckid",
  2325. .callProc = OOMethod_OOEntity_deckid,
  2326. .deleteProc = NULL,
  2327. .cloneProc = NULL
  2328. };
  2329. const static Tcl_MethodType OOMethodType_OOEntity_delete = {
  2330. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2331. .name = "delete",
  2332. .callProc = OOMethod_OOEntity_delete,
  2333. .deleteProc = NULL,
  2334. .cloneProc = NULL
  2335. };
  2336. const static Tcl_MethodType OOMethodType_OOEntity_drawn_reset = {
  2337. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2338. .name = "drawn_reset",
  2339. .callProc = OOMethod_OOEntity_drawn_reset,
  2340. .deleteProc = NULL,
  2341. .cloneProc = NULL
  2342. };
  2343. const static Tcl_MethodType OOMethodType_OOEntity_exists = {
  2344. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2345. .name = "exists",
  2346. .callProc = OOMethod_OOEntity_exists,
  2347. .deleteProc = NULL,
  2348. .cloneProc = NULL
  2349. };
  2350. const static Tcl_MethodType OOMethodType_OOEntity_for = {
  2351. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2352. .name = "for",
  2353. .callProc = OOMethod_OOEntity_for,
  2354. .deleteProc = NULL,
  2355. .cloneProc = NULL
  2356. };
  2357. const static Tcl_MethodType OOMethodType_OOEntity_foreach = {
  2358. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2359. .name = "foreach",
  2360. .callProc = OOMethod_OOEntity_foreach,
  2361. .deleteProc = NULL,
  2362. .cloneProc = NULL
  2363. };
  2364. const static Tcl_MethodType OOMethodType_OOEntity_groupid = {
  2365. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2366. .name = "groupid",
  2367. .callProc = OOMethod_OOEntity_groupid,
  2368. .deleteProc = NULL,
  2369. .cloneProc = NULL
  2370. };
  2371. const static Tcl_MethodType OOMethodType_OOEntity_groups_recalculate = {
  2372. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2373. .name = "groups_recalculate",
  2374. .callProc = OOMethod_OOEntity_groups_recalculate,
  2375. .deleteProc = NULL,
  2376. .cloneProc = NULL
  2377. };
  2378. const static Tcl_MethodType OOMethodType_OOEntity_hidden_inherit = {
  2379. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2380. .name = "hidden_inherit",
  2381. .callProc = OOMethod_OOEntity_hidden_inherit,
  2382. .deleteProc = NULL,
  2383. .cloneProc = NULL
  2384. };
  2385. const static Tcl_MethodType OOMethodType_OOEntity_list = {
  2386. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2387. .name = "list",
  2388. .callProc = OOMethod_OOEntity_list,
  2389. .deleteProc = NULL,
  2390. .cloneProc = NULL
  2391. };
  2392. const static Tcl_MethodType OOMethodType_OOEntity_location = {
  2393. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2394. .name = "location",
  2395. .callProc = OOMethod_OOEntity_location,
  2396. .deleteProc = NULL,
  2397. .cloneProc = NULL
  2398. };
  2399. const static Tcl_MethodType OOMethodType_OOEntity_midpoint = {
  2400. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2401. .name = "midpoint",
  2402. .callProc = OOMethod_OOEntity_midpoint,
  2403. .deleteProc = NULL,
  2404. .cloneProc = NULL
  2405. };
  2406. const static Tcl_MethodType OOMethodType_OOEntity_nodeget = {
  2407. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2408. .name = "nodeget",
  2409. .callProc = OOMethod_OOEntity_nodeget,
  2410. .deleteProc = NULL,
  2411. .cloneProc = NULL
  2412. };
  2413. const static Tcl_MethodType OOMethodType_OOEntity_nodeput = {
  2414. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2415. .name = "nodeput",
  2416. .callProc = OOMethod_OOEntity_nodeput,
  2417. .deleteProc = NULL,
  2418. .cloneProc = NULL
  2419. };
  2420. const static Tcl_MethodType OOMethodType_OOEntity_nodewith = {
  2421. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2422. .name = "nodewith",
  2423. .callProc = OOMethod_OOEntity_nodewith,
  2424. .deleteProc = NULL,
  2425. .cloneProc = NULL
  2426. };
  2427. const static Tcl_MethodType OOMethodType_OOEntity_normalize = {
  2428. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2429. .name = "normalize",
  2430. .callProc = OOMethod_OOEntity_normalize,
  2431. .deleteProc = NULL,
  2432. .cloneProc = NULL
  2433. };
  2434. const static Tcl_MethodType OOMethodType_OOEntity_orientation = {
  2435. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2436. .name = "orientation",
  2437. .callProc = OOMethod_OOEntity_orientation,
  2438. .deleteProc = NULL,
  2439. .cloneProc = NULL
  2440. };
  2441. const static Tcl_MethodType OOMethodType_OOEntity_redraw = {
  2442. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2443. .name = "redraw",
  2444. .callProc = OOMethod_OOEntity_redraw,
  2445. .deleteProc = NULL,
  2446. .cloneProc = NULL
  2447. };
  2448. const static Tcl_MethodType OOMethodType_OOEntity_reset = {
  2449. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2450. .name = "reset",
  2451. .callProc = OOMethod_OOEntity_reset,
  2452. .deleteProc = NULL,
  2453. .cloneProc = NULL
  2454. };
  2455. const static Tcl_MethodType OOMethodType_OOEntity_setting = {
  2456. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2457. .name = "setting",
  2458. .callProc = OOMethod_OOEntity_setting,
  2459. .deleteProc = NULL,
  2460. .cloneProc = NULL
  2461. };
  2462. const static Tcl_MethodType OOMethodType_OOEntity_spec_get = {
  2463. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2464. .name = "spec_get",
  2465. .callProc = OOMethod_OOEntity_spec_get,
  2466. .deleteProc = NULL,
  2467. .cloneProc = NULL
  2468. };
  2469. const static Tcl_MethodType OOMethodType_OOEntity_spec_put = {
  2470. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2471. .name = "spec_put",
  2472. .callProc = OOMethod_OOEntity_spec_put,
  2473. .deleteProc = NULL,
  2474. .cloneProc = NULL
  2475. };
  2476. const static Tcl_MethodType OOMethodType_OOEntity_spec_replace = {
  2477. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2478. .name = "spec_replace",
  2479. .callProc = OOMethod_OOEntity_spec_replace,
  2480. .deleteProc = NULL,
  2481. .cloneProc = NULL
  2482. };
  2483. const static Tcl_MethodType OOMethodType_OOEntity_struct_get = {
  2484. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2485. .name = "struct_get",
  2486. .callProc = OOMethod_OOEntity_struct_get,
  2487. .deleteProc = NULL,
  2488. .cloneProc = NULL
  2489. };
  2490. const static Tcl_MethodType OOMethodType_OOEntity_struct_put = {
  2491. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2492. .name = "struct_put",
  2493. .callProc = OOMethod_OOEntity_struct_put,
  2494. .deleteProc = NULL,
  2495. .cloneProc = NULL
  2496. };
  2497. const static Tcl_MethodType OOMethodType_OOEntity_type = {
  2498. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2499. .name = "type",
  2500. .callProc = OOMethod_OOEntity_type,
  2501. .deleteProc = NULL,
  2502. .cloneProc = NULL
  2503. };
  2504. const static Tcl_MethodType OOMethodType_OOEntity_typeid = {
  2505. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2506. .name = "typeid",
  2507. .callProc = OOMethod_OOEntity_typeid,
  2508. .deleteProc = NULL,
  2509. .cloneProc = NULL
  2510. };
  2511. const static Tcl_MethodType OOMethodType_OOEntity_visible = {
  2512. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2513. .name = "visible",
  2514. .callProc = OOMethod_OOEntity_visible,
  2515. .deleteProc = NULL,
  2516. .cloneProc = NULL
  2517. };
  2518. const static Tcl_MethodType OOMethodType_OOEntity_visible_filter = {
  2519. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2520. .name = "visible_filter",
  2521. .callProc = OOMethod_OOEntity_visible_filter,
  2522. .deleteProc = NULL,
  2523. .cloneProc = NULL
  2524. };
  2525. const static Tcl_MethodType OOMethodType_OOEntity_visible_hidden_subtract = {
  2526. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2527. .name = "visible_hidden_subtract",
  2528. .callProc = OOMethod_OOEntity_visible_hidden_subtract,
  2529. .deleteProc = NULL,
  2530. .cloneProc = NULL
  2531. };
  2532. const static Tcl_MethodType OOMethodType_OOEntity_visible_inherit = {
  2533. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2534. .name = "visible_inherit",
  2535. .callProc = OOMethod_OOEntity_visible_inherit,
  2536. .deleteProc = NULL,
  2537. .cloneProc = NULL
  2538. };
  2539. const static Tcl_MethodType OOMethodType_OOEntity_visible_reset = {
  2540. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2541. .name = "visible_reset",
  2542. .callProc = OOMethod_OOEntity_visible_reset,
  2543. .deleteProc = NULL,
  2544. .cloneProc = NULL
  2545. };
  2546. const static Tcl_MethodType OOMethodType_OOEntity_visible_tree = {
  2547. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2548. .name = "visible_tree",
  2549. .callProc = OOMethod_OOEntity_visible_tree,
  2550. .deleteProc = NULL,
  2551. .cloneProc = NULL
  2552. };
  2553. const static Tcl_MethodType OOMethodType_OOEntity_witheach = {
  2554. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2555. .name = "witheach",
  2556. .callProc = OOMethod_OOEntity_witheach,
  2557. .deleteProc = NULL,
  2558. .cloneProc = NULL
  2559. };
  2560. const static Tcl_MethodType OOMethodType_SimType_C_Init = {
  2561. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2562. .name = "C_Init",
  2563. .callProc = OOMethod_SimType_C_Init,
  2564. .deleteProc = NULL,
  2565. .cloneProc = NULL
  2566. };
  2567. const static Tcl_MethodType OOMethodType_SimType_children = {
  2568. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2569. .name = "children",
  2570. .callProc = OOMethod_SimType_children,
  2571. .deleteProc = NULL,
  2572. .cloneProc = NULL
  2573. };
  2574. const static Tcl_MethodType OOMethodType_SimType_count = {
  2575. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2576. .name = "count",
  2577. .callProc = OOMethod_SimType_count,
  2578. .deleteProc = NULL,
  2579. .cloneProc = NULL
  2580. };
  2581. const static Tcl_MethodType OOMethodType_SimType_create = {
  2582. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2583. .name = "create",
  2584. .callProc = OOMethod_SimType_create,
  2585. .deleteProc = NULL,
  2586. .cloneProc = NULL
  2587. };
  2588. const static Tcl_MethodType OOMethodType_SimType_delete = {
  2589. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2590. .name = "delete",
  2591. .callProc = OOMethod_SimType_delete,
  2592. .deleteProc = NULL,
  2593. .cloneProc = NULL
  2594. };
  2595. const static Tcl_MethodType OOMethodType_SimType_exists = {
  2596. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2597. .name = "exists",
  2598. .callProc = OOMethod_SimType_exists,
  2599. .deleteProc = NULL,
  2600. .cloneProc = NULL
  2601. };
  2602. const static Tcl_MethodType OOMethodType_SimType_for = {
  2603. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2604. .name = "for",
  2605. .callProc = OOMethod_SimType_for,
  2606. .deleteProc = NULL,
  2607. .cloneProc = NULL
  2608. };
  2609. const static Tcl_MethodType OOMethodType_SimType_foreach = {
  2610. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2611. .name = "foreach",
  2612. .callProc = OOMethod_SimType_foreach,
  2613. .deleteProc = NULL,
  2614. .cloneProc = NULL
  2615. };
  2616. const static Tcl_MethodType OOMethodType_SimType_groupid = {
  2617. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2618. .name = "groupid",
  2619. .callProc = OOMethod_SimType_groupid,
  2620. .deleteProc = NULL,
  2621. .cloneProc = NULL
  2622. };
  2623. const static Tcl_MethodType OOMethodType_SimType_list = {
  2624. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2625. .name = "list",
  2626. .callProc = OOMethod_SimType_list,
  2627. .deleteProc = NULL,
  2628. .cloneProc = NULL
  2629. };
  2630. const static Tcl_MethodType OOMethodType_SimType_nodeget = {
  2631. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2632. .name = "nodeget",
  2633. .callProc = OOMethod_SimType_nodeget,
  2634. .deleteProc = NULL,
  2635. .cloneProc = NULL
  2636. };
  2637. const static Tcl_MethodType OOMethodType_SimType_nodeput = {
  2638. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2639. .name = "nodeput",
  2640. .callProc = OOMethod_SimType_nodeput,
  2641. .deleteProc = NULL,
  2642. .cloneProc = NULL
  2643. };
  2644. const static Tcl_MethodType OOMethodType_SimType_nodewith = {
  2645. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2646. .name = "nodewith",
  2647. .callProc = OOMethod_SimType_nodewith,
  2648. .deleteProc = NULL,
  2649. .cloneProc = NULL
  2650. };
  2651. const static Tcl_MethodType OOMethodType_SimType_normalize = {
  2652. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2653. .name = "normalize",
  2654. .callProc = OOMethod_SimType_normalize,
  2655. .deleteProc = NULL,
  2656. .cloneProc = NULL
  2657. };
  2658. const static Tcl_MethodType OOMethodType_SimType_parent = {
  2659. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2660. .name = "parent",
  2661. .callProc = OOMethod_SimType_parent,
  2662. .deleteProc = NULL,
  2663. .cloneProc = NULL
  2664. };
  2665. const static Tcl_MethodType OOMethodType_SimType_setting = {
  2666. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2667. .name = "setting",
  2668. .callProc = OOMethod_SimType_setting,
  2669. .deleteProc = NULL,
  2670. .cloneProc = NULL
  2671. };
  2672. const static Tcl_MethodType OOMethodType_SimType_spec_get = {
  2673. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2674. .name = "spec_get",
  2675. .callProc = OOMethod_SimType_spec_get,
  2676. .deleteProc = NULL,
  2677. .cloneProc = NULL
  2678. };
  2679. const static Tcl_MethodType OOMethodType_SimType_spec_put = {
  2680. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2681. .name = "spec_put",
  2682. .callProc = OOMethod_SimType_spec_put,
  2683. .deleteProc = NULL,
  2684. .cloneProc = NULL
  2685. };
  2686. const static Tcl_MethodType OOMethodType_SimType_spec_replace = {
  2687. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2688. .name = "spec_replace",
  2689. .callProc = OOMethod_SimType_spec_replace,
  2690. .deleteProc = NULL,
  2691. .cloneProc = NULL
  2692. };
  2693. const static Tcl_MethodType OOMethodType_SimType_struct_get = {
  2694. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2695. .name = "struct_get",
  2696. .callProc = OOMethod_SimType_struct_get,
  2697. .deleteProc = NULL,
  2698. .cloneProc = NULL
  2699. };
  2700. const static Tcl_MethodType OOMethodType_SimType_struct_put = {
  2701. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2702. .name = "struct_put",
  2703. .callProc = OOMethod_SimType_struct_put,
  2704. .deleteProc = NULL,
  2705. .cloneProc = NULL
  2706. };
  2707. const static Tcl_MethodType OOMethodType_SimType_type = {
  2708. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2709. .name = "type",
  2710. .callProc = OOMethod_SimType_type,
  2711. .deleteProc = NULL,
  2712. .cloneProc = NULL
  2713. };
  2714. const static Tcl_MethodType OOMethodType_SimType_typeid = {
  2715. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2716. .name = "typeid",
  2717. .callProc = OOMethod_SimType_typeid,
  2718. .deleteProc = NULL,
  2719. .cloneProc = NULL
  2720. };
  2721. const static Tcl_MethodType OOMethodType_SimType_visible_reset = {
  2722. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2723. .name = "visible_reset",
  2724. .callProc = OOMethod_SimType_visible_reset,
  2725. .deleteProc = NULL,
  2726. .cloneProc = NULL
  2727. };
  2728. const static Tcl_MethodType OOMethodType_SimType_witheach = {
  2729. .version = TCL_OO_METADATA_VERSION_CURRENT,
  2730. .name = "witheach",
  2731. .callProc = OOMethod_SimType_witheach,
  2732. .deleteProc = NULL,
  2733. .cloneProc = NULL
  2734. };
  2735. /* END generate-cfile-constant */
  2736. /* BEGIN generate-cfile-functions */
  2737. /* *Odie_Alloc */
  2738. void *Odie_Alloc(unsigned int size){
  2739. /*
  2740. ** Provide wrappers around malloc and free
  2741. */
  2742. void *p;
  2743. p=(void *)ckalloc(size);
  2744. memset(p,0,size);
  2745. return p;
  2746. }
  2747. /*
  2748. ** Hash and comparison functions when the mode is READI_HASH_INT
  2749. */
  2750. static int intHash(const void *pKey, int nKey){
  2751. return nKey ^ (nKey<<8) ^ (nKey>>8);
  2752. }
  2753. static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){
  2754. return n2 - n1;
  2755. }
  2756.  
  2757. /*
  2758. ** Hash and comparison functions when the mode is READI_HASH_POINTER
  2759. */
  2760. static int ptrHash(const void *pKey, int nKey){
  2761. uptr x = Addr(pKey);
  2762. return x ^ (x<<8) ^ (x>>8);
  2763. }
  2764. static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
  2765. if( pKey1==pKey2 ) return 0;
  2766. if( pKey1<pKey2 ) return -1;
  2767. return 1;
  2768. }
  2769.  
  2770. /*
  2771. ** Hash and comparison functions when the mode is READI_HASH_BINARY
  2772. */
  2773. static int binHash(const void *pKey, int nKey){
  2774. int h = 0;
  2775. const char *z = (const char *)pKey;
  2776. while( nKey-- > 0 ){
  2777. h = (h<<3) ^ h ^ *(z++);
  2778. }
  2779. return h & 0x7fffffff;
  2780. }
  2781. static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){
  2782. if( n1!=n2 ) return n2-n1;
  2783. return memcmp(pKey1,pKey2,n1);
  2784. }
  2785.  
  2786. /*
  2787. ** Return a pointer to the appropriate hash function given the key class.
  2788. **
  2789. ** The C syntax in this function definition may be unfamilar to some
  2790. ** programmers, so we provide the following additional explanation:
  2791. **
  2792. ** The name of the function is "hashFunction". The function takes a
  2793. ** single parameter "keyClass". The return value of hashFunction()
  2794. ** is a pointer to another function. Specifically, the return value
  2795. ** of hashFunction() is a pointer to a function that takes two parameters
  2796. ** with types "const void*" and "int" and returns an "int".
  2797. */
  2798. static int (*hashFunction(int keyClass))(const void*,int){
  2799. switch( keyClass ){
  2800. case READI_HASH_INT: return &intHash;
  2801. case READI_HASH_POINTER: return &ptrHash;
  2802. case READI_HASH_BINARY: return &binHash;;
  2803. default: break;
  2804. }
  2805. return 0;
  2806. }
  2807.  
  2808. /*
  2809. ** Return a pointer to the appropriate hash function given the key class.
  2810. **
  2811. ** For help in interpreted the obscure C code in the function definition,
  2812. ** see the header comment on the previous function.
  2813. */
  2814. static int (*compareFunction(int keyClass))(const void*,int,const void*,int){
  2815. switch( keyClass ){
  2816. case READI_HASH_INT: return &intCompare;
  2817. case READI_HASH_POINTER: return &ptrCompare;
  2818. case READI_HASH_BINARY: return &binCompare;
  2819. default: break;
  2820. }
  2821. return 0;
  2822. }
  2823.  
  2824.  
  2825. /* Resize the hash table so that it cantains "new_size" buckets.
  2826. ** "new_size" must be a power of 2. The hash table might fail
  2827. ** to resize if Odie_Alloc() fails.
  2828. */
  2829. static void rehash(Hash *pH, int new_size){
  2830. struct _ht *new_ht; /* The new hash table */
  2831. HashElem *elem, *next_elem; /* For looping over existing elements */
  2832. HashElem *x; /* Element being copied to new hash table */
  2833. int (*xHash)(const void*,int); /* The hash function */
  2834.  
  2835. assert( (new_size & (new_size-1))==0 );
  2836. new_ht = (struct _ht *)Odie_Alloc( new_size*sizeof(struct _ht) );
  2837. if( new_ht==0 ) return;
  2838. memset(new_ht, 0, new_size*sizeof(struct _ht));
  2839. if( pH->ht ) Odie_Free((char *)pH->ht);
  2840. pH->ht = new_ht;
  2841. pH->htsize = new_size;
  2842. xHash = hashFunction(pH->keyClass);
  2843. for(elem=pH->first, pH->first=0; elem; elem = next_elem){
  2844. int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1);
  2845. next_elem = elem->next;
  2846. x = new_ht[h].chain;
  2847. if( x ){
  2848. elem->next = x;
  2849. elem->prev = x->prev;
  2850. if( x->prev ) x->prev->next = elem;
  2851. else pH->first = elem;
  2852. x->prev = elem;
  2853. }else{
  2854. elem->next = pH->first;
  2855. if( pH->first ) pH->first->prev = elem;
  2856. elem->prev = 0;
  2857. pH->first = elem;
  2858. }
  2859. new_ht[h].chain = elem;
  2860. new_ht[h].count++;
  2861. }
  2862. }
  2863.  
  2864. /* This function (for internal use only) locates an element in an
  2865. ** hash table that matches the given key. The hash for this key has
  2866. ** already been computed and is passed as the 4th parameter.
  2867. */
  2868. static HashElem *findElementGivenHash(
  2869. const Hash *pH, /* The pH to be searched */
  2870. const void *pKey, /* The key we are searching for */
  2871. int nKey,
  2872. int h /* The hash for this key. */
  2873. ){
  2874. HashElem *elem; /* Used to loop thru the element list */
  2875. int count; /* Number of elements left to test */
  2876. int (*xCompare)(const void*,int,const void*,int); /* comparison function */
  2877.  
  2878. if( pH->ht ){
  2879. elem = pH->ht[h].chain;
  2880. count = pH->ht[h].count;
  2881. xCompare = compareFunction(pH->keyClass);
  2882. while( count-- && elem ){
  2883. if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
  2884. return elem;
  2885. }
  2886. elem = elem->next;
  2887. }
  2888. }
  2889. return 0;
  2890. }
  2891.  
  2892. /* Remove a single entry from the hash table given a pointer to that
  2893. ** element and a hash on the element's key.
  2894. */
  2895. static void removeElementGivenHash(
  2896. Hash *pH, /* The pH containing "elem" */
  2897. HashElem* elem, /* The element to be removed from the pH */
  2898. int h /* Hash value for the element */
  2899. ){
  2900. if( elem->prev ){
  2901. elem->prev->next = elem->next;
  2902. }else{
  2903. pH->first = elem->next;
  2904. }
  2905. if( elem->next ){
  2906. elem->next->prev = elem->prev;
  2907. }
  2908. if( pH->ht[h].chain==elem ){
  2909. pH->ht[h].chain = elem->next;
  2910. }
  2911. pH->ht[h].count--;
  2912. if( pH->ht[h].count<=0 ){
  2913. pH->ht[h].chain = 0;
  2914. }
  2915. if( pH->copyKey && elem->pKey ){
  2916. Odie_Free((char *)elem->pKey);
  2917. }
  2918. Odie_Free((char *) elem );
  2919. pH->count--;
  2920. }
  2921. /* readiHashNoCase */
  2922. int readiHashNoCase(const void *pKey, int nKey){
  2923. const char *z = (const char *)pKey;
  2924. int h = 0;
  2925. if( nKey<=0 ) nKey = strlen(z);
  2926. while( nKey > 0 ){
  2927. h = (h<<3) ^ h ^ tolower(*z++);
  2928. nKey--;
  2929. }
  2930. return h & 0x7fffffff;
  2931. }
  2932. /* readiHashInit */
  2933. void readiHashInit(Hash *new, int keyClass, int copyKey){
  2934.  
  2935. assert( new!=0 );
  2936. assert( keyClass>=READI_HASH_INT && keyClass<=READI_HASH_BINARY );
  2937. new->keyClass = keyClass;
  2938. new->copyKey = copyKey && keyClass==READI_HASH_BINARY;
  2939. new->first = 0;
  2940. new->count = 0;
  2941. new->htsize = 0;
  2942. new->ht = 0;
  2943. }
  2944. /* readiHashClear */
  2945. void readiHashClear(Hash *pH){
  2946. HashElem *elem; /* For looping over all elements of the table */
  2947.  
  2948. assert( pH!=0 );
  2949. elem = pH->first;
  2950. pH->first = 0;
  2951. if( pH->ht ) Odie_Free((char *)pH->ht);
  2952. pH->ht = 0;
  2953. pH->htsize = 0;
  2954. while( elem ){
  2955. HashElem *next_elem = elem->next;
  2956. if( pH->copyKey && elem->pKey ){
  2957. Odie_Free((char *)elem->pKey);
  2958. }
  2959. Odie_Free((char *)elem);
  2960. elem = next_elem;
  2961. }
  2962. pH->count = 0;
  2963. }
  2964. /* *readiHashFind */
  2965. void *readiHashFind(const Hash *pH, const void *pKey, int nKey){
  2966. int h; /* A hash on key */
  2967. HashElem *elem; /* The element that matches key */
  2968. int (*xHash)(const void*,int); /* The hash function */
  2969.  
  2970. if( pH==0 || pH->ht==0 ) return 0;
  2971. xHash = hashFunction(pH->keyClass);
  2972. assert( xHash!=0 );
  2973. h = (*xHash)(pKey,nKey);
  2974. assert( (pH->htsize & (pH->htsize-1))==0 );
  2975. elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1));
  2976. return elem ? elem->data : 0;
  2977. }
  2978. /* *readiHashInsert */
  2979. void *readiHashInsert(Hash *pH, const void *pKey, int nKey, void *data){
  2980. int hraw; /* Raw hash value of the key */
  2981. int h; /* the hash of the key modulo hash table size */
  2982. HashElem *elem; /* Used to loop thru the element list */
  2983. HashElem *new_elem; /* New element added to the pH */
  2984. int (*xHash)(const void*,int); /* The hash function */
  2985.  
  2986. assert( pH!=0 );
  2987. xHash = hashFunction(pH->keyClass);
  2988. assert( xHash!=0 );
  2989. hraw = (*xHash)(pKey, nKey);
  2990. assert( (pH->htsize & (pH->htsize-1))==0 );
  2991. h = hraw & (pH->htsize-1);
  2992. elem = findElementGivenHash(pH,pKey,nKey,h);
  2993. if( elem ){
  2994. void *old_data = elem->data;
  2995. if( data==0 ){
  2996. removeElementGivenHash(pH,elem,h);
  2997. }else{
  2998. elem->data = data;
  2999. }
  3000. return old_data;
  3001. }
  3002. if( data==0 ) return 0;
  3003. new_elem = (HashElem*)Odie_Alloc( sizeof(HashElem) );
  3004. if( new_elem==0 ) return data;
  3005.  
  3006. if( pH->copyKey && pKey!=0 ){
  3007. new_elem->pKey = Odie_Alloc( nKey );
  3008. if( new_elem->pKey==0 ){
  3009. Odie_Free((char *)new_elem);
  3010. return data;
  3011. }
  3012. memcpy((void*)new_elem->pKey, pKey, nKey);
  3013. }else{
  3014. new_elem->pKey = (void*)pKey;
  3015. }
  3016. new_elem->nKey = nKey;
  3017. pH->count++;
  3018. if( pH->htsize==0 ) rehash(pH,8);
  3019. if( pH->htsize==0 ){
  3020. pH->count = 0;
  3021. Odie_Free((char *)new_elem);
  3022. return data;
  3023. }
  3024. if( pH->count > pH->htsize ){
  3025. rehash(pH,pH->htsize*2);
  3026. }
  3027. assert( (pH->htsize & (pH->htsize-1))==0 );
  3028. h = hraw & (pH->htsize-1);
  3029. elem = pH->ht[h].chain;
  3030. if( elem ){
  3031. new_elem->next = elem;
  3032. new_elem->prev = elem->prev;
  3033. if( elem->prev ){ elem->prev->next = new_elem; }
  3034. else { pH->first = new_elem; }
  3035. elem->prev = new_elem;
  3036. }else{
  3037. new_elem->next = pH->first;
  3038. new_elem->prev = 0;
  3039. if( pH->first ){ pH->first->prev = new_elem; }
  3040. pH->first = new_elem;
  3041. }
  3042. pH->ht[h].count++;
  3043. pH->ht[h].chain = new_elem;
  3044. new_elem->data = data;
  3045. return 0;
  3046. }
  3047. /* int */
  3048. void TreeInit(Tree *tree, int (*xCompare)(const void*, const void*),void *(*xCopy)(const void*),void (*xFree)(void*)){
  3049. /* Turn bulk memory into a Tree structure
  3050. Tree *tree, Tree object to initialize
  3051. int (*xCompare)(const void*, const void*), Comparison function
  3052. void *(*xCopy)(const void*), Key copy function or NULL
  3053. void (*xFree)(void*) Key delete function or NULL
  3054. */
  3055. tree->xCompare = xCompare;
  3056. tree->xCopy = xCopy;
  3057. tree->xFree = xFree;
  3058. tree->top = 0;
  3059. }
  3060. /* TreeCount */
  3061. int TreeCount(Tree *pTree){
  3062. /* Return the number of elements in the tree. */
  3063. if( pTree && pTree->top ){
  3064. return pTree->top->weight;
  3065. }else{
  3066. return 0;
  3067. }
  3068. }
  3069. /* void */
  3070. static void TreeClearNode(TreeElem *p, void (*xFree)(void*)){
  3071. /* Delete a single node of the binary tree and all of its children */
  3072. if( p==0 ) return;
  3073. if( p->left ) TreeClearNode(p->left, xFree);
  3074. if( p->right ) TreeClearNode(p->right, xFree);
  3075. if( xFree ){
  3076. xFree(p->key);
  3077. }
  3078. Tcl_Free((char *)p);
  3079. }
  3080. /* TreeClear */
  3081. void TreeClear(Tree *tree){
  3082. /* Remove all nodes from a tree */
  3083. if( tree->top ){
  3084. TreeClearNode(tree->top, tree->xFree);
  3085. }
  3086. tree->top = 0;
  3087. }
  3088. /* *TreeFind */
  3089. void *TreeFind(Tree *tree, const void *key){
  3090. /* Find the element of the tree (if any) whose key matches "key".
  3091. ** Return a pointer to the data for that element. If no match
  3092. ** is found, return NULL.
  3093. */
  3094. TreeElem *p;
  3095.  
  3096. p = tree->top;
  3097. while( p ){
  3098. int c = tree->xCompare(p->key, key);
  3099. if( c==0 ){
  3100. return p->data;
  3101. }else if( c<0 ){
  3102. p = p->right;
  3103. }else{
  3104. p = p->left;
  3105. }
  3106. }
  3107. return 0;
  3108. }
  3109. /* TreeRank */
  3110. int TreeRank(Tree *tree, const void *key){
  3111. /* If the node with key "key" is the left-most element of the tree,
  3112. ** return 0. If it is the second to the left, return 1. And so
  3113. ** forth.
  3114. **
  3115. ** If there is no node in the tree with the key "key", then return
  3116. ** the number that would have been returned if such a node were
  3117. ** inserted.
  3118. */
  3119. TreeElem *p;
  3120. int rank = 0;
  3121.  
  3122. p = tree->top;
  3123. while( p ){
  3124. int c = tree->xCompare(p->key, key);
  3125. if( c==0 ){
  3126. rank += p->left ? p->left->weight: 0;
  3127. break;
  3128. }else if( c<0 ){
  3129. rank += (p->left ? p->left->weight: 0) + 1;
  3130. p = p->right;
  3131. }else{
  3132. p = p->left;
  3133. }
  3134. }
  3135. return rank;
  3136. }
  3137. /* *TreeFindNthElem */
  3138. static TreeElem *TreeFindNthElem(Tree *tree, int n){
  3139. /* Return a pointer to the N-th element of a tree. (The left-most
  3140. ** element is number 0, the next is number 1 and so forth.)
  3141. */
  3142. TreeElem *p;
  3143.  
  3144. p = tree->top;
  3145. while( p ){
  3146. int c = p->left ? p->left->weight : 0;
  3147. if( n==c ){
  3148. return p;
  3149. }else if( n>c ){
  3150. n -= c+1;
  3151. p = p->right;
  3152. }else{
  3153. p = p->left;
  3154. }
  3155. }
  3156. return 0;
  3157. }
  3158. /* *TreeData */
  3159. void *TreeData(Tree *tree, int n){
  3160. /* Return the data associated with the N-th element of the tree. Return
  3161. ** NULL if there is no N-th element.
  3162. */
  3163. TreeElem *p = TreeFindNthElem(tree,n);
  3164. return p ? p->data : 0;
  3165. }
  3166. /* *TreeKey */
  3167. const void *TreeKey(Tree *tree, int n){
  3168. /* Return the key associated with the N-th element of the tree. Return
  3169. ** NULL if there is no N-th element.
  3170. */
  3171. TreeElem *p = TreeFindNthElem(tree,n);
  3172. if( p ){
  3173. return p->key;
  3174. }else{
  3175. return 0;
  3176. }
  3177. }
  3178. /* TreeBalance */
  3179. static void TreeBalance(TreeElem **ppElem){
  3180. /*
  3181. ** Definitions:
  3182. ** WEIGHT
  3183. ** The weight of a node is the total number of children for the node
  3184. ** plus 1. Leaf nodes have a weight of 1. The root node has a weight
  3185. ** which equals the number of nodes in the tree.
  3186. **
  3187. ** BALANCE
  3188. ** A node is balanced if the weight of the one child is not more than
  3189. ** twice the weight of the other child.
  3190. */
  3191.  
  3192. /* The following routine rebalances the tree rooted at *ppElem after
  3193. ** the insertion or deletion of a single ancestor.
  3194. */
  3195. TreeElem *n; /* Pointer to self */
  3196. int l,r; /* Weight of left and right daughters */
  3197. int a,b; /* Weights of various nodes */
  3198.  
  3199. if( ppElem==0 || (n=*ppElem)==0 ) return;
  3200. l = n->left ? n->left->weight: 0;
  3201. r = n->right ? n->right->weight: 0;
  3202. if( l>r*2 ){ /* Too heavy on the left side */
  3203. TreeElem *nl; /* Pointer to left daughter */
  3204. TreeElem *nr; /* Pointer to right daughter */
  3205. int ll, lr; /* Weight of left daughter's left and right daughter */
  3206. nl = n->left;
  3207. ll = nl->left ? nl->left->weight: 0;
  3208. lr = nl->right ? nl->right->weight: 0;
  3209. if( ll>lr || nl->right==0 ){
  3210. /*
  3211. ** Convert from: n to: nl
  3212. ** / \ / ** nl c a n
  3213. ** / \ / ** a b b c
  3214. */
  3215. n->left = nl->right;
  3216. nl->right = n;
  3217. n->weight = a = r + lr + 1;
  3218. nl->weight = a + ll + 1;
  3219. *ppElem = nl;
  3220. }else{
  3221. /*
  3222. ** Convert from: n to: nr
  3223. ** / \ / ** nl d nl n
  3224. ** / \ / \ / ** a nr a b c d
  3225. ** / ** b c
  3226. */
  3227. int lrl, lrr; /* Weight of Great-granddaughter nodes */
  3228. nr = nl->right;
  3229. lrl = nr->left ? nr->left->weight: 0;
  3230. lrr = nr->right ? nr->right->weight: 0;
  3231. nl->right = nr->left;
  3232. nr->left = nl;
  3233. n->left = nr->right;
  3234. nr->right = n;
  3235. n->weight = a = lrr + r + 1;
  3236. nl->weight = b = ll + lrl + 1;
  3237. nr->weight = a + b + 1;
  3238. *ppElem = nr;
  3239. }
  3240. }else if( r>l*2 ){/* Too deep on the right side */
  3241. TreeElem *nl; /* Pointer to left daughter */
  3242. TreeElem *nr; /* Pointer to right daughter */
  3243. int rl, rr; /* Weight of right daughter's left and right daughter */
  3244. nr = n->right;
  3245. rl = nr->left ? nr->left->weight: 0;
  3246. rr = nr->right ? nr->right->weight: 0;
  3247. if( rr>rl || nr->left==0 ){
  3248. /*
  3249. ** Convert from: n to: nr
  3250. ** / \ / ** a nr n c
  3251. ** / \ / ** b c a b
  3252. */
  3253. n->right = nr->left;
  3254. nr->left = n;
  3255. n->weight = a = l + rl + 1;
  3256. nr->weight = a + rr + 1;
  3257. *ppElem = nr;
  3258. }else{
  3259. /*
  3260. ** Convert from: n to: nl
  3261. ** / \ / ** a nr n nr
  3262. ** / \ / \ / ** nl d a b c d
  3263. ** / ** b c
  3264. */
  3265. int rll,rlr; /* Weights of great-granddaughter nodes */
  3266. nl = nr->left;
  3267. rll = nl->left ? nl->left->weight: 0;
  3268. rlr = nl->right ? nl->right->weight: 0;
  3269. nr->left = nl->right;
  3270. nl->right = nr;
  3271. n->right = nl->left;
  3272. nl->left = n;
  3273. n->weight = a = l + rll + 1;
  3274. nr->weight = b = rr + rlr + 1;
  3275. nl->weight = a + b + 1;
  3276. *ppElem = nl;
  3277. }
  3278. }else{ /* Node is already balanced. Just recompute its weight. */
  3279. n->weight = l + r + 1;
  3280. }
  3281. }
  3282. /* *TreeInsertElement */
  3283. static void *TreeInsertElement(Tree *pTree, void *key, void *data){
  3284. /*
  3285. Tree *pTree, The root of the tree
  3286. void *key, Insert data at this key
  3287. void *data Data to be inserted
  3288. */
  3289. /* This routine either changes the data on an existing node in the tree,
  3290. ** or inserts a new node. "key" identifies the node. If the data on
  3291. ** an existing node is changed, then the function returns the old data.
  3292. ** If a new node is created, NULL is returned.
  3293. */
  3294. TreeElem *n;
  3295. void *old = 0;
  3296. TreeElem **h[100]; /* Sufficient for a tree with up to 4.0E+17 nodes */
  3297. int level = 0;
  3298.  
  3299.  
  3300. h[0] = &pTree->top;
  3301. level = 1;
  3302. n = pTree->top;
  3303. while( n ){
  3304. int c;
  3305. c = pTree->xCompare(key, n->key);
  3306. if( c<0 ){
  3307. h[level++] = &(n->left);
  3308. n = n->left;
  3309. }else if( c>0 ){
  3310. h[level++] = &(n->right);
  3311. n = n->right;
  3312. }else{
  3313. old = n->data;
  3314. n->data = data; /* Replace data in an existing node */
  3315. break;
  3316. }
  3317. }
  3318. if( n==0 ){ /* Insert a leaf node */
  3319. level--;
  3320. n = *h[level] = (TreeElem *)Tcl_Alloc( sizeof(TreeElem) );
  3321. if( n==0 ){
  3322. return data;
  3323. }
  3324. n->data = data;
  3325. if( pTree->xCopy ){
  3326. n->key = pTree->xCopy(key);
  3327. }else{
  3328. n->key = key;
  3329. }
  3330. n->left = n->right = 0;
  3331. while( level>=0 ) TreeBalance(h[level--]);
  3332. }
  3333. return old;
  3334. }
  3335. /* *TreeDeleteNthElem */
  3336. static TreeElem *TreeDeleteNthElem(TreeElem **ppTop, int N){
  3337. /* Unlink the N-th node of the tree and return a pointer to that
  3338. ** node. (The left-most node is 0, the next node to the right is
  3339. ** 1 and so forth.)
  3340. */
  3341. TreeElem *p; /* For walking the tree */
  3342. int level = 0; /* Depth of the blancing stack */
  3343. TreeElem **h[100]; /* Balance stack. 100 is sufficient for balancing
  3344. ** a tree with up to 4.0E+17 nodes */
  3345.  
  3346. h[0] = ppTop;
  3347. level = 1;
  3348. p = *ppTop;
  3349. while( p ){
  3350. int w;
  3351. w = (p->left ? p->left->weight: 0);
  3352. if( N>w ){
  3353. h[level++] = &(p->right);
  3354. p = p->right;
  3355. N -= w+1;
  3356. }else if( N<w ){
  3357. h[level++] = &(p->left);
  3358. p = p->left;
  3359. }else{
  3360. break;
  3361. }
  3362. }
  3363. if( p ){
  3364. level--;
  3365. if( p->left==0 ){
  3366. *h[level] = p->right;
  3367. level--;
  3368. }else if( p->right==0 ){
  3369. *h[level] = p->left;
  3370. level--;
  3371. }else{
  3372. TreeElem *x;
  3373. x = TreeDeleteNthElem(&(p->right),0);
  3374. x->right = p->right;
  3375. x->left = p->left;
  3376. *h[level] = x;
  3377. }
  3378. while( level>=0 ) TreeBalance(h[level--]);
  3379. }
  3380. return p;
  3381. }
  3382. /* *TreeDeleteElem */
  3383. static TreeElem *TreeDeleteElem(Tree *tree, const void *key){
  3384. /* Unlink the node of the tree corresponding to key and return a pointer
  3385. ** to that node.
  3386. */
  3387. TreeElem *p; /* For walking the tree */
  3388. int level = 0; /* Depth of the blancing stack */
  3389. TreeElem **h[100]; /* Balance stack. 100 is sufficient for balancing
  3390. ** a tree with up to 4.0E+17 nodes */
  3391.  
  3392. h[0] = &tree->top;
  3393. level = 1;
  3394. p = tree->top;
  3395. while( p ){
  3396. int w;
  3397. w = tree->xCompare(p->key, key);
  3398. if( w<0 ){
  3399. h[level++] = &(p->right);
  3400. p = p->right;
  3401. }else if( w>0 ){
  3402. h[level++] = &(p->left);
  3403. p = p->left;
  3404. }else{
  3405. break;
  3406. }
  3407. }
  3408. if( p ){
  3409. level--;
  3410. if( p->left==0 ){
  3411. *h[level] = p->right;
  3412. level--;
  3413. }else if( p->right==0 ){
  3414. *h[level] = p->left;
  3415. level--;
  3416. }else{
  3417. TreeElem *x;
  3418. x = TreeDeleteNthElem(&(p->right),0);
  3419. x->right = p->right;
  3420. x->left = p->left;
  3421. *h[level] = x;
  3422. }
  3423. while( level>=0 ) TreeBalance(h[level--]);
  3424. }
  3425. return p;
  3426. }
  3427. /* *TreeInsert */
  3428. void *TreeInsert(Tree *tree, void *key, void *data){
  3429. /* Insert new data into a node of the tree. The node is identified
  3430. ** by "key".
  3431. **
  3432. ** If the new data is NULL, then node is deleted.
  3433. **
  3434. ** If the node aready exists, the new data overwrites the old and
  3435. ** the old data is returned. If the node doesn't already exist, then
  3436. ** a new node is created and the function returns NULL.
  3437. */
  3438.  
  3439. void *old;
  3440. if( data==0 ){
  3441. TreeElem *elem = TreeDeleteElem(tree, key);
  3442. if( elem ){
  3443. if( tree->xFree ){
  3444. tree->xFree(elem->key);
  3445. }
  3446. old = elem->data;
  3447. Tcl_Free((char *)elem);
  3448. }else{
  3449. old = 0;
  3450. }
  3451. }else{
  3452. old = TreeInsertElement(tree,key,data);
  3453. }
  3454. return old;
  3455. }
  3456. /* *TreeChangeNth */
  3457. void *TreeChangeNth(Tree *tree, int n, void *data){
  3458. /* Change the data on the n-th node of the tree. The old data
  3459. ** is returned.
  3460. **
  3461. ** If data==NULL, then the n-th node of the tree is deleted. (The
  3462. ** data associated with that node is still returned.)
  3463. **
  3464. ** If the value N is out-of-bounds, then no new node is created.
  3465. ** Instead, the "data" parameter is returned.
  3466. */
  3467. void *old;
  3468. if( data==0 ){
  3469. TreeElem *elem = TreeDeleteNthElem(&tree->top,n);
  3470. if( elem ){
  3471. if( tree->xFree ){
  3472. tree->xFree(elem->key);
  3473. }
  3474. old = elem->data;
  3475. Tcl_Free((char *)elem);
  3476. }else{
  3477. old = 0;
  3478. }
  3479. }else{
  3480. TreeElem *elem = TreeFindNthElem(tree,n);
  3481. if( elem ){
  3482. old = elem->data;
  3483. elem->data = data;
  3484. }else{
  3485. old = data;
  3486. }
  3487. }
  3488. return old;
  3489. }
  3490. /* Odie_GetMatrixElementFromObj */
  3491. static inline int Odie_GetMatrixElementFromObj(Tcl_Interp *interp,Tcl_Obj *objPtr,double *R,int idx){
  3492. double temp;
  3493. if( Tcl_GetDoubleFromObj(interp, objPtr, &temp) ) return TCL_ERROR;
  3494. R[idx]=temp;
  3495. return TCL_OK;
  3496. }
  3497. /* hashInt */
  3498. static inline unsigned int hashInt(int x){
  3499. /*
  3500. ** Compute a hash on an integer.
  3501. */
  3502. return (x & 0x7fffffff) % SZ_HASH;
  3503. }
  3504. /* intCoord */
  3505. static inline long intCoord(double x){
  3506. /*
  3507. ** Round a coordinate to its nearest grain boundary
  3508. */
  3509. long idxX = x/OdieGrain + (x>0.0 ? 0.5 : -0.5);
  3510. return idxX*OdieGrain;
  3511. }
  3512. /* hashPoint */
  3513. static inline unsigned int hashPoint(VECTORXY p){
  3514. /*
  3515. ** Compute a hash on a point.
  3516. */
  3517. long x=intCoord(p[X_IDX])*ODIE_X_HASH;
  3518. long y=intCoord(p[Y_IDX])*ODIE_Y_HASH;
  3519. return hashInt(x ^ y);
  3520. }
  3521. /* hashVectorXY */
  3522. static inline unsigned int hashVectorXY(VECTORXY p){
  3523. long x=intCoord(p[X_IDX])*ODIE_X_HASH;
  3524. long y=intCoord(p[Y_IDX])*ODIE_Y_HASH;
  3525. return hashInt(x ^ y);
  3526. }
  3527. /* hashVectorXYZ */
  3528. static inline unsigned int hashVectorXYZ(VECTORXYZ p){
  3529. long x=intCoord(p[X_IDX])*ODIE_X_HASH;
  3530. long y=intCoord(p[Y_IDX])*ODIE_Y_HASH;
  3531. long z=intCoord(p[Z_IDX])*ODIE_Z_HASH;
  3532. if(z!=0) {
  3533. return hashInt(x ^ y ^ z);
  3534. } else {
  3535. return hashInt(x ^ y);
  3536. }
  3537. }
  3538. /* roundCoord */
  3539. static inline double roundCoord(double x){
  3540. return intCoord(x);
  3541. }
  3542. /* hashCoord */
  3543. static inline int hashCoord(double x, double y){
  3544. /*
  3545. ** Compute a hash on a pair of floating point number.
  3546. */
  3547. long idxX = intCoord(x)*ODIE_X_HASH;
  3548. long idxY = intCoord(y)*ODIE_Y_HASH;
  3549. return hashInt(idxX ^ idxY);
  3550. }
  3551. /* hashCoord3d */
  3552. static inline int hashCoord3d(double x, double y,double z){
  3553. /*
  3554. ** Compute a hash on a pair of floating point number.
  3555. */
  3556. long idxX = intCoord(x)*ODIE_X_HASH;
  3557. long idxY = intCoord(y)*ODIE_Y_HASH;
  3558. long idxZ = intCoord(z)*ODIE_Z_HASH;
  3559. if(idxZ!=0) {
  3560. return hashInt(idxX ^ idxY ^ idxZ);
  3561. } else {
  3562. return hashInt(idxX ^ idxY);
  3563. }
  3564. }
  3565. /* floatCompare */
  3566. static inline int floatCompare(double x0, double x1){
  3567. /*
  3568. ** Compare to floating point values and return negative, zero, or
  3569. ** positive if the first value is less than, equal to, or greater
  3570. ** than the second.
  3571. */
  3572. double diff = x1 - x0;
  3573. if( diff>-OdieGrain && diff<OdieGrain ){
  3574. diff = 0.0;
  3575. }
  3576. return (int)diff;
  3577. }
  3578. /* GridCoord */
  3579. static inline void GridCoord(double *x, double *y){
  3580. /*
  3581. ** Round a set of coordinates by OdieGrain
  3582. */
  3583. *x=round(*x/OdieGrain)*OdieGrain;
  3584. *y=round(*y/OdieGrain)*OdieGrain;
  3585. }
  3586. /* Math_Const_Init */
  3587. int Math_Const_Init(Tcl_Interp *interp){
  3588. Tcl_Obj *varname=Tcl_NewStringObj("math_const",-1);
  3589. Tcl_IncrRefCount(varname);
  3590. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_2_x_pi",-1),Tcl_NewDoubleObj(M_2_X_PI),TCL_GLOBAL_ONLY);
  3591. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_pi_180",-1),Tcl_NewDoubleObj(M_PI_180),TCL_GLOBAL_ONLY);
  3592. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_pi_360",-1),Tcl_NewDoubleObj(M_PI_360),TCL_GLOBAL_ONLY);
  3593. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_e",-1),Tcl_NewDoubleObj(M_E),TCL_GLOBAL_ONLY);
  3594. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_log2e",-1),Tcl_NewDoubleObj(M_LOG2E),TCL_GLOBAL_ONLY);
  3595. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_log10e",-1),Tcl_NewDoubleObj(M_LOG10E),TCL_GLOBAL_ONLY);
  3596. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_ln2",-1),Tcl_NewDoubleObj(M_LN2),TCL_GLOBAL_ONLY);
  3597. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_ln10",-1),Tcl_NewDoubleObj(M_LN10),TCL_GLOBAL_ONLY);
  3598. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_pi",-1),Tcl_NewDoubleObj(M_PI),TCL_GLOBAL_ONLY);
  3599. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_pi_2",-1),Tcl_NewDoubleObj(M_PI_2),TCL_GLOBAL_ONLY);
  3600. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_pi_4",-1),Tcl_NewDoubleObj(M_PI_4),TCL_GLOBAL_ONLY);
  3601. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_1_pi",-1),Tcl_NewDoubleObj(M_1_PI),TCL_GLOBAL_ONLY);
  3602. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_2_pi",-1),Tcl_NewDoubleObj(M_2_PI),TCL_GLOBAL_ONLY);
  3603. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_2_sqrtpi",-1),Tcl_NewDoubleObj(M_2_SQRTPI),TCL_GLOBAL_ONLY);
  3604. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_sqrt2",-1),Tcl_NewDoubleObj(M_SQRT2),TCL_GLOBAL_ONLY);
  3605. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_sqrt1_2",-1),Tcl_NewDoubleObj(M_SQRT1_2),TCL_GLOBAL_ONLY);
  3606. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_sqrt3",-1),Tcl_NewDoubleObj(M_SQRT3),TCL_GLOBAL_ONLY);
  3607. Tcl_ObjSetVar2(interp,varname,Tcl_NewStringObj("m_sqrt3_2",-1),Tcl_NewDoubleObj(M_SQRT3_2),TCL_GLOBAL_ONLY);
  3608. Tcl_DecrRefCount(varname);
  3609. return TCL_OK;}
  3610. /* VectorXYZ_AABB_Normalize */
  3611. static inline void VectorXYZ_AABB_Normalize(AABBXYZ R){
  3612. double temp;
  3613. if (R[X_MIN_IDX] > R[X_MAX_IDX]) {
  3614. temp=R[X_MIN_IDX];
  3615. R[X_MIN_IDX]=R[X_MAX_IDX];
  3616. R[X_MAX_IDX]=temp;
  3617. } if (R[Y_MIN_IDX] > R[Y_MAX_IDX]) {
  3618. temp=R[Y_MIN_IDX];
  3619. R[Y_MIN_IDX]=R[Y_MAX_IDX];
  3620. R[Y_MAX_IDX]=temp;
  3621. } if (R[Z_MIN_IDX] > R[Z_MAX_IDX]) {
  3622. temp=R[Z_MIN_IDX];
  3623. R[Z_MIN_IDX]=R[Z_MAX_IDX];
  3624. R[Z_MAX_IDX]=temp;
  3625. }}
  3626. /* VectorXYZ_AABB_Copy */
  3627. static void VectorXYZ_AABB_Copy(AABBXYZ dest,AABBXYZ src){
  3628. dest[X_MIN_IDX]=src[X_MIN_IDX];
  3629. dest[X_MAX_IDX]=src[X_MAX_IDX];
  3630. dest[Y_MIN_IDX]=src[Y_MIN_IDX];
  3631. dest[Y_MAX_IDX]=src[Y_MAX_IDX];
  3632. dest[Z_MIN_IDX]=src[Z_MIN_IDX];
  3633. dest[Z_MAX_IDX]=src[Z_MAX_IDX];
  3634. }
  3635. /* VectorXYZ_AABB_Within */
  3636. static inline int VectorXYZ_AABB_Within(VectorXYZ POINT,AABBXYZ R){
  3637. if (POINT[X_IDX]<R[X_MIN_IDX]) return 0;
  3638. if (POINT[X_IDX]>R[X_MAX_IDX]) return 0;
  3639. if (POINT[Y_IDX]<R[Y_MIN_IDX]) return 0;
  3640. if (POINT[Y_IDX]>R[Y_MAX_IDX]) return 0;
  3641. if (POINT[Z_IDX]<R[Z_MIN_IDX]) return 0;
  3642. if (POINT[Z_IDX]>R[Z_MAX_IDX]) return 0;
  3643. return 1;
  3644. }
  3645. /* VectorXYZ_BBOX_Overlap_TwoVectors */
  3646. static inline int VectorXYZ_BBOX_Overlap_TwoVectors(VectorXYZ A1,VectorXYZ A2,VectorXYZ B1,VectorXYZ B2){
  3647. if (A1[X_IDX]<B1[X_IDX] && A1[X_IDX]<B2[X_IDX]) {
  3648. if (A2[X_IDX]<B1[X_IDX] && A2[X_IDX]<B2[X_IDX]) return 0;
  3649. }
  3650. if (A1[X_IDX]>B1[X_IDX] && A1[X_IDX]>B2[X_IDX]) {
  3651. if (A2[X_IDX]>B1[X_IDX] && A2[X_IDX]>B2[X_IDX]) return 0;
  3652. }
  3653. if (A1[Y_IDX]<B1[Y_IDX] && A1[Y_IDX]<B2[Y_IDX]) {
  3654. if (A2[Y_IDX]<B1[Y_IDX] && A2[Y_IDX]<B2[Y_IDX]) return 0;
  3655. }
  3656. if (A1[Y_IDX]>B1[Y_IDX] && A1[Y_IDX]>B2[Y_IDX]) {
  3657. if (A2[Y_IDX]>B1[Y_IDX] && A2[Y_IDX]>B2[Y_IDX]) return 0;
  3658. }
  3659. if (A1[Z_IDX]<B1[Z_IDX] && A1[Z_IDX]<B2[Z_IDX]) {
  3660. if (A2[Z_IDX]<B1[Z_IDX] && A2[Z_IDX]<B2[Z_IDX]) return 0;
  3661. }
  3662. if (A1[Z_IDX]>B1[Z_IDX] && A1[Z_IDX]>B2[Z_IDX]) {
  3663. if (A2[Z_IDX]>B1[Z_IDX] && A2[Z_IDX]>B2[Z_IDX]) return 0;
  3664. }
  3665. return 1;
  3666. }
  3667. /* AABB_AABB_Intersect */
  3668. static inline int AABB_AABB_Intersect(AABBXYZ A,AABBXYZ B){
  3669. int a_inside_b=0;
  3670. int b_inside_a=0;
  3671. if (A[X_MIN_IDX]>=B[X_MIN_IDX] && A[X_MAX_IDX]<=B[X_MAX_IDX]) a_inside_b++;
  3672. if (B[X_MIN_IDX]>=A[X_MIN_IDX] && B[X_MAX_IDX]<=A[X_MAX_IDX]) b_inside_a++;
  3673. if (A[Y_MIN_IDX]>=B[Y_MIN_IDX] && A[Y_MAX_IDX]<=B[Y_MAX_IDX]) a_inside_b++;
  3674. if (B[Y_MIN_IDX]>=A[Y_MIN_IDX] && B[Y_MAX_IDX]<=A[Y_MAX_IDX]) b_inside_a++;
  3675. if (A[Z_MIN_IDX]>=B[Z_MIN_IDX] && A[Z_MAX_IDX]<=B[Z_MAX_IDX]) a_inside_b++;
  3676. if (B[Z_MIN_IDX]>=A[Z_MIN_IDX] && B[Z_MAX_IDX]<=A[Z_MAX_IDX]) b_inside_a++;
  3677.  
  3678. if (a_inside_b==0 && b_inside_a==0) return 0;
  3679. if (a_inside_b==3 && b_inside_a==3) return 2;
  3680. if (a_inside_b==3) return 3;
  3681. if (b_inside_a==3) return 4;
  3682. return 1;
  3683. }
  3684. /* VectorXYZ_AABB_Measure */
  3685. static inline void VectorXYZ_AABB_Measure(VectorXYZ POINT,AABBXYZ R){
  3686. if (POINT[X_IDX]<R[X_MIN_IDX]) R[X_MIN_IDX]=POINT[X_IDX];
  3687. if (POINT[X_IDX]>R[X_MAX_IDX]) R[X_MAX_IDX]=POINT[X_IDX];
  3688. if (POINT[Y_IDX]<R[Y_MIN_IDX]) R[Y_MIN_IDX]=POINT[Y_IDX];
  3689. if (POINT[Y_IDX]>R[Y_MAX_IDX]) R[Y_MAX_IDX]=POINT[Y_IDX];
  3690. if (POINT[Z_IDX]<R[Z_MIN_IDX]) R[Z_MIN_IDX]=POINT[Z_IDX];
  3691. if (POINT[Z_IDX]>R[Z_MAX_IDX]) R[Z_MAX_IDX]=POINT[Z_IDX];
  3692. }
  3693. /* AABB_AABB_Combine */
  3694. static inline void AABB_AABB_Combine(AABBXYZ B,AABBXYZ A){
  3695. if (A[X_MIN_IDX]<B[X_MIN_IDX]) B[X_MIN_IDX]=A[X_MIN_IDX];
  3696. if (A[X_MAX_IDX]>B[X_MAX_IDX]) B[X_MAX_IDX]=A[X_MAX_IDX];
  3697. if (A[Y_MIN_IDX]<B[Y_MIN_IDX]) B[Y_MIN_IDX]=A[Y_MIN_IDX];
  3698. if (A[Y_MAX_IDX]>B[Y_MAX_IDX]) B[Y_MAX_IDX]=A[Y_MAX_IDX];
  3699. if (A[Z_MIN_IDX]<B[Z_MIN_IDX]) B[Z_MIN_IDX]=A[Z_MIN_IDX];
  3700. if (A[Z_MAX_IDX]>B[Z_MAX_IDX]) B[Z_MAX_IDX]=A[Z_MAX_IDX];
  3701. }
  3702. /* VectorXYZ_AABB_Reset */
  3703. static inline void VectorXYZ_AABB_Reset(AABBXYZ R){
  3704. R[X_MIN_IDX]=R[Y_MIN_IDX]=R[Z_MIN_IDX]=1e99;
  3705. R[X_MAX_IDX]=R[Y_MAX_IDX]=R[Z_MAX_IDX]=-1e99;
  3706. }
  3707. VectorXYZ Odie_Up_Direction = {0, 0, 1.0};
  3708. /* *Matrix_To_affine */
  3709. const char *Matrix_To_affine(Odie_MatrixObj *matrix,int form){
  3710. if(matrix->form==MATFORM_affine) {
  3711. return NULL;
  3712. }
  3713. if(matrix->form==MATFORM_euler) {
  3714. VectorXYZ TEMP;
  3715. VectorXYZ_Copy(TEMP,matrix->matrix);
  3716. affine_Rotate_From_Euler(TEMP,matrix->matrix);
  3717. matrix->form=MATFORM_affine;
  3718. return NULL;
  3719. }
  3720. if(matrix->form==MATFORM_vector_xyz) {
  3721. VectorXYZ TEMP;
  3722. VectorXYZ_Copy(TEMP,matrix->matrix);
  3723. Odie_Affine4x4_Translation(TEMP,matrix->matrix);
  3724. matrix->form=MATFORM_affine;
  3725. return NULL;
  3726. }
  3727. if(matrix->rows==4 && matrix->cols==4) {
  3728. if(matrix->form==MATFORM_null) {
  3729. matrix->form=MATFORM_affine;
  3730. }
  3731. return NULL;
  3732. }
  3733. if(matrix->rows==1 && matrix->cols==16) {
  3734. if(matrix->form==MATFORM_null) {
  3735. matrix->form=MATFORM_affine;
  3736. }
  3737. return NULL;
  3738. }
  3739. if(matrix->rows==16 && matrix->cols==1) {
  3740. if(matrix->form==MATFORM_null) {
  3741. matrix->form=MATFORM_affine;
  3742. }
  3743. return NULL;
  3744. }
  3745. return "Cannot convert to affine";
  3746. }
  3747. /* affine_Compare */
  3748. static inline int affine_Compare(AFFINE A,AFFINE B){
  3749. if(fabs(B[AFFINE_IDX_0_0]-A[AFFINE_IDX_0_0])>__FLT_EPSILON__) return 0;
  3750. if(fabs(B[AFFINE_IDX_0_1]-A[AFFINE_IDX_0_1])>__FLT_EPSILON__) return 0;
  3751. if(fabs(B[AFFINE_IDX_0_2]-A[AFFINE_IDX_0_2])>__FLT_EPSILON__) return 0;
  3752. if(fabs(B[AFFINE_IDX_0_3]-A[AFFINE_IDX_0_3])>__FLT_EPSILON__) return 0;
  3753. if(fabs(B[AFFINE_IDX_1_0]-A[AFFINE_IDX_1_0])>__FLT_EPSILON__) return 0;
  3754. if(fabs(B[AFFINE_IDX_1_1]-A[AFFINE_IDX_1_1])>__FLT_EPSILON__) return 0;
  3755. if(fabs(B[AFFINE_IDX_1_2]-A[AFFINE_IDX_1_2])>__FLT_EPSILON__) return 0;
  3756. if(fabs(B[AFFINE_IDX_1_3]-A[AFFINE_IDX_1_3])>__FLT_EPSILON__) return 0;
  3757. if(fabs(B[AFFINE_IDX_2_0]-A[AFFINE_IDX_2_0])>__FLT_EPSILON__) return 0;
  3758. if(fabs(B[AFFINE_IDX_2_1]-A[AFFINE_IDX_2_1])>__FLT_EPSILON__) return 0;
  3759. if(fabs(B[AFFINE_IDX_2_2]-A[AFFINE_IDX_2_2])>__FLT_EPSILON__) return 0;
  3760. if(fabs(B[AFFINE_IDX_2_3]-A[AFFINE_IDX_2_3])>__FLT_EPSILON__) return 0;
  3761. if(fabs(B[AFFINE_IDX_3_0]-A[AFFINE_IDX_3_0])>__FLT_EPSILON__) return 0;
  3762. if(fabs(B[AFFINE_IDX_3_1]-A[AFFINE_IDX_3_1])>__FLT_EPSILON__) return 0;
  3763. if(fabs(B[AFFINE_IDX_3_2]-A[AFFINE_IDX_3_2])>__FLT_EPSILON__) return 0;
  3764. if(fabs(B[AFFINE_IDX_3_3]-A[AFFINE_IDX_3_3])>__FLT_EPSILON__) return 0;
  3765. return 1;
  3766. }
  3767. /* Odie_Affine4x4_Copy */
  3768. inline extern void Odie_Affine4x4_Copy(AFFINE RESULT,AFFINE A){
  3769. RESULT[AFFINE_IDX_0_0]=A[AFFINE_IDX_0_0];
  3770. RESULT[AFFINE_IDX_0_1]=A[AFFINE_IDX_0_1];
  3771. RESULT[AFFINE_IDX_0_2]=A[AFFINE_IDX_0_2];
  3772. RESULT[AFFINE_IDX_0_3]=A[AFFINE_IDX_0_3];
  3773. RESULT[AFFINE_IDX_1_0]=A[AFFINE_IDX_1_0];
  3774. RESULT[AFFINE_IDX_1_1]=A[AFFINE_IDX_1_1];
  3775. RESULT[AFFINE_IDX_1_2]=A[AFFINE_IDX_1_2];
  3776. RESULT[AFFINE_IDX_1_3]=A[AFFINE_IDX_1_3];
  3777. RESULT[AFFINE_IDX_2_0]=A[AFFINE_IDX_2_0];
  3778. RESULT[AFFINE_IDX_2_1]=A[AFFINE_IDX_2_1];
  3779. RESULT[AFFINE_IDX_2_2]=A[AFFINE_IDX_2_2];
  3780. RESULT[AFFINE_IDX_2_3]=A[AFFINE_IDX_2_3];
  3781. RESULT[AFFINE_IDX_3_0]=A[AFFINE_IDX_3_0];
  3782. RESULT[AFFINE_IDX_3_1]=A[AFFINE_IDX_3_1];
  3783. RESULT[AFFINE_IDX_3_2]=A[AFFINE_IDX_3_2];
  3784. RESULT[AFFINE_IDX_3_3]=A[AFFINE_IDX_3_3];
  3785. }
  3786. /* affine_ZeroMatrix */
  3787. inline extern void affine_ZeroMatrix(AFFINE A){
  3788. A[AFFINE_IDX_0_0]=0.0;
  3789. A[AFFINE_IDX_0_1]=0.0;
  3790. A[AFFINE_IDX_0_2]=0.0;
  3791. A[AFFINE_IDX_0_3]=0.0;
  3792. A[AFFINE_IDX_1_0]=0.0;
  3793. A[AFFINE_IDX_1_1]=0.0;
  3794. A[AFFINE_IDX_1_2]=0.0;
  3795. A[AFFINE_IDX_1_3]=0.0;
  3796. A[AFFINE_IDX_2_0]=0.0;
  3797. A[AFFINE_IDX_2_1]=0.0;
  3798. A[AFFINE_IDX_2_2]=0.0;
  3799. A[AFFINE_IDX_2_3]=0.0;
  3800. A[AFFINE_IDX_3_0]=0.0;
  3801. A[AFFINE_IDX_3_1]=0.0;
  3802. A[AFFINE_IDX_3_2]=0.0;
  3803. A[AFFINE_IDX_3_3]=0.0;
  3804. }
  3805. /* Odie_Affine4x4_Identity */
  3806. inline extern void Odie_Affine4x4_Identity(AFFINE A){
  3807. A[AFFINE_IDX_0_0]=1.0;
  3808. A[AFFINE_IDX_0_1]=0.0;
  3809. A[AFFINE_IDX_0_2]=0.0;
  3810. A[AFFINE_IDX_0_3]=0.0;
  3811. A[AFFINE_IDX_1_0]=0.0;
  3812. A[AFFINE_IDX_1_1]=1.0;
  3813. A[AFFINE_IDX_1_2]=0.0;
  3814. A[AFFINE_IDX_1_3]=0.0;
  3815. A[AFFINE_IDX_2_0]=0.0;
  3816. A[AFFINE_IDX_2_1]=0.0;
  3817. A[AFFINE_IDX_2_2]=1.0;
  3818. A[AFFINE_IDX_2_3]=0.0;
  3819. A[AFFINE_IDX_3_0]=0.0;
  3820. A[AFFINE_IDX_3_1]=0.0;
  3821. A[AFFINE_IDX_3_2]=0.0;
  3822. A[AFFINE_IDX_3_3]=1.0;
  3823. }
  3824. /* Odie_Affine4x4_Translation */
  3825. void Odie_Affine4x4_Translation(AFFINE RESULT,VECTOR A){
  3826. Odie_Affine4x4_Identity(RESULT);
  3827. RESULT[AFFINE_IDX_0_3]=-A[X_IDX];
  3828. RESULT[AFFINE_IDX_1_3]=-A[Y_IDX];
  3829. RESULT[AFFINE_IDX_2_3]=-A[Z_IDX];
  3830. }
  3831. /* Odie_Affine4x4_Scale */
  3832. inline extern void Odie_Affine4x4_Scale(AFFINE RESULT,VECTOR A){
  3833. Odie_Affine4x4_Identity(RESULT);
  3834. RESULT[AFFINE_IDX_0_0]=A[X_IDX];
  3835. RESULT[AFFINE_IDX_1_1]=A[Y_IDX];
  3836. RESULT[AFFINE_IDX_2_2]=A[Z_IDX];
  3837. RESULT[AFFINE_IDX_3_3]=1.0;
  3838. }
  3839. /* affine_rotate_nutation */
  3840. inline extern void affine_rotate_nutation(AFFINE RESULT,SCALER theta){
  3841. double cos_theta,sin_theta;
  3842. cos_theta=cos(theta);
  3843. sin_theta=sin(theta);
  3844.  
  3845. Odie_Affine4x4_Identity(RESULT);
  3846. RESULT[AFFINE_IDX_1_1]=cos_theta;
  3847. RESULT[AFFINE_IDX_1_2]=sin_theta;
  3848. RESULT[AFFINE_IDX_2_1]=-sin_theta;
  3849. RESULT[AFFINE_IDX_2_2]=cos_theta;
  3850. }
  3851. /* affine_rotate_precession */
  3852. inline extern void affine_rotate_precession(AFFINE RESULT,SCALER phi){
  3853. double cos_phi,sin_phi;
  3854. cos_phi=cos(phi);
  3855. sin_phi=sin(phi);
  3856.  
  3857. Odie_Affine4x4_Identity(RESULT);
  3858. RESULT[AFFINE_IDX_0_0]=cos_phi;
  3859. RESULT[AFFINE_IDX_0_1]=sin_phi;
  3860. RESULT[AFFINE_IDX_1_0]=-sin_phi;
  3861. RESULT[AFFINE_IDX_1_1]=cos_phi;
  3862. }
  3863. /* affine_rotate_spin */
  3864. static inline void affine_rotate_spin(AFFINE RESULT,SCALER psi){
  3865. double cos_psi,sin_psi;
  3866. cos_psi=cos(psi);
  3867. sin_psi=sin(psi);
  3868.  
  3869. Odie_Affine4x4_Identity(RESULT);
  3870. RESULT[AFFINE_IDX_0_0]=cos_psi;
  3871. RESULT[AFFINE_IDX_0_1]=sin_psi;
  3872. RESULT[AFFINE_IDX_1_0]=-sin_psi;
  3873. RESULT[AFFINE_IDX_1_1]=cos_psi;
  3874. }
  3875. /* affine_Rotate_From_Euler */
  3876. void affine_Rotate_From_Euler(AFFINE RESULT,VECTOR rotate){
  3877. double cos_theta,sin_theta;
  3878. double cos_phi,sin_phi;
  3879. double cos_psi,sin_psi;
  3880. cos_theta=cos(rotate[EULER_THETA]);
  3881. sin_theta=sin(rotate[EULER_THETA]);
  3882. cos_phi=cos(rotate[EULER_PHI]);
  3883. sin_phi=sin(rotate[EULER_PHI]);
  3884. cos_psi=cos(rotate[EULER_PSI]);
  3885. sin_psi=sin(rotate[EULER_PSI]);
  3886. RESULT[AFFINE_IDX_0_0]=cos_psi*cos_phi-cos_theta*sin_psi*sin_psi;
  3887. RESULT[AFFINE_IDX_0_1]=cos_psi*sin_phi+cos_theta*cos_phi*sin_psi;
  3888. RESULT[AFFINE_IDX_0_2]=sin_theta*sin_psi;
  3889. RESULT[AFFINE_IDX_0_3]=0.0;
  3890. RESULT[AFFINE_IDX_1_0]=-sin_psi*cos_phi-cos_theta*sin_phi*cos_psi;
  3891. RESULT[AFFINE_IDX_1_1]=-sin_psi*sin_phi+cos_theta*cos_phi*cos_psi;
  3892. RESULT[AFFINE_IDX_1_2]=sin_theta*cos_psi;
  3893. RESULT[AFFINE_IDX_1_3]=0.0;
  3894. RESULT[AFFINE_IDX_2_0]=sin_phi*sin_theta;
  3895. RESULT[AFFINE_IDX_2_1]=-cos_phi*sin_theta;
  3896. RESULT[AFFINE_IDX_2_2]=cos_theta;
  3897. RESULT[AFFINE_IDX_2_3]=0.0;
  3898. RESULT[AFFINE_IDX_3_0]=0.0;
  3899. RESULT[AFFINE_IDX_3_1]=0.0;
  3900. RESULT[AFFINE_IDX_3_2]=0.0;
  3901. RESULT[AFFINE_IDX_3_3]=1.0;
  3902. }
  3903. /* Odie_Affine4x4_Multiply */
  3904. inline extern void Odie_Affine4x4_Multiply(AFFINE R,AFFINE A,AFFINE B){
  3905. double cell_0_0;
  3906. double cell_0_1;
  3907. double cell_0_2;
  3908. double cell_0_3;
  3909. double cell_1_0;
  3910. double cell_1_1;
  3911. double cell_1_2;
  3912. double cell_1_3;
  3913. double cell_2_0;
  3914. double cell_2_1;
  3915. double cell_2_2;
  3916. double cell_2_3;
  3917. double cell_3_0;
  3918. double cell_3_1;
  3919. double cell_3_2;
  3920. double cell_3_3;
  3921. cell_0_0=A[AFFINE_IDX_0_0]*B[AFFINE_IDX_0_0]+A[AFFINE_IDX_0_1]*B[AFFINE_IDX_1_0]+A[AFFINE_IDX_0_2]*B[AFFINE_IDX_2_0]+A[AFFINE_IDX_0_3]*B[AFFINE_IDX_3_0];
  3922. cell_0_1=A[AFFINE_IDX_0_0]*B[AFFINE_IDX_0_1]+A[AFFINE_IDX_0_1]*B[AFFINE_IDX_1_1]+A[AFFINE_IDX_0_2]*B[AFFINE_IDX_2_1]+A[AFFINE_IDX_0_3]*B[AFFINE_IDX_3_1];
  3923. cell_0_2=A[AFFINE_IDX_0_0]*B[AFFINE_IDX_0_2]+A[AFFINE_IDX_0_1]*B[AFFINE_IDX_1_2]+A[AFFINE_IDX_0_2]*B[AFFINE_IDX_2_2]+A[AFFINE_IDX_0_3]*B[AFFINE_IDX_3_2];
  3924. cell_0_3=A[AFFINE_IDX_0_0]*B[AFFINE_IDX_0_3]+A[AFFINE_IDX_0_1]*B[AFFINE_IDX_1_3]+A[AFFINE_IDX_0_2]*B[AFFINE_IDX_2_3]+A[AFFINE_IDX_0_3]*B[AFFINE_IDX_3_3];
  3925. cell_1_0=A[AFFINE_IDX_1_0]*B[AFFINE_IDX_0_0]+A[AFFINE_IDX_1_1]*B[AFFINE_IDX_1_0]+A[AFFINE_IDX_1_2]*B[AFFINE_IDX_2_0]+A[AFFINE_IDX_1_3]*B[AFFINE_IDX_3_0];
  3926. cell_1_1=A[AFFINE_IDX_1_0]*B[AFFINE_IDX_0_1]+A[AFFINE_IDX_1_1]*B[AFFINE_IDX_1_1]+A[AFFINE_IDX_1_2]*B[AFFINE_IDX_2_1]+A[AFFINE_IDX_1_3]*B[AFFINE_IDX_3_1];
  3927. cell_1_2=A[AFFINE_IDX_1_0]*B[AFFINE_IDX_0_2]+A[AFFINE_IDX_1_1]*B[AFFINE_IDX_1_2]+A[AFFINE_IDX_1_2]*B[AFFINE_IDX_2_2]+A[AFFINE_IDX_1_3]*B[AFFINE_IDX_3_2];
  3928. cell_1_3=A[AFFINE_IDX_1_0]*B[AFFINE_IDX_0_3]+A[AFFINE_IDX_1_1]*B[AFFINE_IDX_1_3]+A[AFFINE_IDX_1_2]*B[AFFINE_IDX_2_3]+A[AFFINE_IDX_1_3]*B[AFFINE_IDX_3_3];
  3929. cell_2_0=A[AFFINE_IDX_2_0]*B[AFFINE_IDX_0_0]+A[AFFINE_IDX_2_1]*B[AFFINE_IDX_1_0]+A[AFFINE_IDX_2_2]*B[AFFINE_IDX_2_0]+A[AFFINE_IDX_2_3]*B[AFFINE_IDX_3_0];
  3930. cell_2_1=A[AFFINE_IDX_2_0]*B[AFFINE_IDX_0_1]+A[AFFINE_IDX_2_1]*B[AFFINE_IDX_1_1]+A[AFFINE_IDX_2_2]*B[AFFINE_IDX_2_1]+A[AFFINE_IDX_2_3]*B[AFFINE_IDX_3_1];
  3931. cell_2_2=A[AFFINE_IDX_2_0]*B[AFFINE_IDX_0_2]+A[AFFINE_IDX_2_1]*B[AFFINE_IDX_1_2]+A[AFFINE_IDX_2_2]*B[AFFINE_IDX_2_2]+A[AFFINE_IDX_2_3]*B[AFFINE_IDX_3_2];
  3932. cell_2_3=A[AFFINE_IDX_2_0]*B[AFFINE_IDX_0_3]+A[AFFINE_IDX_2_1]*B[AFFINE_IDX_1_3]+A[AFFINE_IDX_2_2]*B[AFFINE_IDX_2_3]+A[AFFINE_IDX_2_3]*B[AFFINE_IDX_3_3];
  3933. cell_3_0=A[AFFINE_IDX_3_0]*B[AFFINE_IDX_0_0]+A[AFFINE_IDX_3_1]*B[AFFINE_IDX_1_0]+A[AFFINE_IDX_3_2]*B[AFFINE_IDX_2_0]+A[AFFINE_IDX_3_3]*B[AFFINE_IDX_3_0];
  3934. cell_3_1=A[AFFINE_IDX_3_0]*B[AFFINE_IDX_0_1]+A[AFFINE_IDX_3_1]*B[AFFINE_IDX_1_1]+A[AFFINE_IDX_3_2]*B[AFFINE_IDX_2_1]+A[AFFINE_IDX_3_3]*B[AFFINE_IDX_3_1];
  3935. cell_3_2=A[AFFINE_IDX_3_0]*B[AFFINE_IDX_0_2]+A[AFFINE_IDX_3_1]*B[AFFINE_IDX_1_2]+A[AFFINE_IDX_3_2]*B[AFFINE_IDX_2_2]+A[AFFINE_IDX_3_3]*B[AFFINE_IDX_3_2];
  3936. cell_3_3=A[AFFINE_IDX_3_0]*B[AFFINE_IDX_0_3]+A[AFFINE_IDX_3_1]*B[AFFINE_IDX_1_3]+A[AFFINE_IDX_3_2]*B[AFFINE_IDX_2_3]+A[AFFINE_IDX_3_3]*B[AFFINE_IDX_3_3];
  3937. R[AFFINE_IDX_0_0]=cell_0_0;
  3938. R[AFFINE_IDX_0_1]=cell_0_1;
  3939. R[AFFINE_IDX_0_2]=cell_0_2;
  3940. R[AFFINE_IDX_0_3]=cell_0_3;
  3941. R[AFFINE_IDX_1_0]=cell_1_0;
  3942. R[AFFINE_IDX_1_1]=cell_1_1;
  3943. R[AFFINE_IDX_1_2]=cell_1_2;
  3944. R[AFFINE_IDX_1_3]=cell_1_3;
  3945. R[AFFINE_IDX_2_0]=cell_2_0;
  3946. R[AFFINE_IDX_2_1]=cell_2_1;
  3947. R[AFFINE_IDX_2_2]=cell_2_2;
  3948. R[AFFINE_IDX_2_3]=cell_2_3;
  3949. R[AFFINE_IDX_3_0]=cell_3_0;
  3950. R[AFFINE_IDX_3_1]=cell_3_1;
  3951. R[AFFINE_IDX_3_2]=cell_3_2;
  3952. R[AFFINE_IDX_3_3]=cell_3_3;
  3953. }
  3954. /* Odie_Affine4x4_Inverse */
  3955. int Odie_Affine4x4_Inverse(AFFINE r, AFFINE m){
  3956. double d00, d01, d02, d03;
  3957. double d10, d11, d12, d13;
  3958. double d20, d21, d22, d23;
  3959. double d30, d31, d32, d33;
  3960. double m00, m01, m02, m03;
  3961. double m10, m11, m12, m13;
  3962. double m20, m21, m22, m23;
  3963. double m30, m31, m32, m33;
  3964. double D;
  3965.  
  3966. m00 = m[AFFINE_IDX_0_0]; m01 = m[AFFINE_IDX_0_1]; m02 = m[AFFINE_IDX_0_2]; m03 = m[AFFINE_IDX_0_3];
  3967. m10 = m[AFFINE_IDX_1_0]; m11 = m[AFFINE_IDX_1_1]; m12 = m[AFFINE_IDX_1_2]; m13 = m[AFFINE_IDX_1_3];
  3968. m20 = m[AFFINE_IDX_2_0]; m21 = m[AFFINE_IDX_2_1]; m22 = m[AFFINE_IDX_2_2]; m23 = m[AFFINE_IDX_2_3];
  3969. m30 = m[AFFINE_IDX_3_0]; m31 = m[AFFINE_IDX_3_1]; m32 = m[AFFINE_IDX_3_2]; m33 = m[AFFINE_IDX_3_3];
  3970.  
  3971. d00 = m11*m22*m33 + m12*m23*m31 + m13*m21*m32 - m31*m22*m13 - m32*m23*m11 - m33*m21*m12;
  3972. d01 = m10*m22*m33 + m12*m23*m30 + m13*m20*m32 - m30*m22*m13 - m32*m23*m10 - m33*m20*m12;
  3973. d02 = m10*m21*m33 + m11*m23*m30 + m13*m20*m31 - m30*m21*m13 - m31*m23*m10 - m33*m20*m11;
  3974. d03 = m10*m21*m32 + m11*m22*m30 + m12*m20*m31 - m30*m21*m12 - m31*m22*m10 - m32*m20*m11;
  3975.  
  3976. d10 = m01*m22*m33 + m02*m23*m31 + m03*m21*m32 - m31*m22*m03 - m32*m23*m01 - m33*m21*m02;
  3977. d11 = m00*m22*m33 + m02*m23*m30 + m03*m20*m32 - m30*m22*m03 - m32*m23*m00 - m33*m20*m02;
  3978. d12 = m00*m21*m33 + m01*m23*m30 + m03*m20*m31 - m30*m21*m03 - m31*m23*m00 - m33*m20*m01;
  3979. d13 = m00*m21*m32 + m01*m22*m30 + m02*m20*m31 - m30*m21*m02 - m31*m22*m00 - m32*m20*m01;
  3980.  
  3981. d20 = m01*m12*m33 + m02*m13*m31 + m03*m11*m32 - m31*m12*m03 - m32*m13*m01 - m33*m11*m02;
  3982. d21 = m00*m12*m33 + m02*m13*m30 + m03*m10*m32 - m30*m12*m03 - m32*m13*m00 - m33*m10*m02;
  3983. d22 = m00*m11*m33 + m01*m13*m30 + m03*m10*m31 - m30*m11*m03 - m31*m13*m00 - m33*m10*m01;
  3984. d23 = m00*m11*m32 + m01*m12*m30 + m02*m10*m31 - m30*m11*m02 - m31*m12*m00 - m32*m10*m01;
  3985.  
  3986. d30 = m01*m12*m23 + m02*m13*m21 + m03*m11*m22 - m21*m12*m03 - m22*m13*m01 - m23*m11*m02;
  3987. d31 = m00*m12*m23 + m02*m13*m20 + m03*m10*m22 - m20*m12*m03 - m22*m13*m00 - m23*m10*m02;
  3988. d32 = m00*m11*m23 + m01*m13*m20 + m03*m10*m21 - m20*m11*m03 - m21*m13*m00 - m23*m10*m01;
  3989. d33 = m00*m11*m22 + m01*m12*m20 + m02*m10*m21 - m20*m11*m02 - m21*m12*m00 - m22*m10*m01;
  3990.  
  3991. D = m00*d00 - m01*d01 + m02*d02 - m03*d03;
  3992.  
  3993.  
  3994. if (D == 0.0)
  3995. {
  3996. /* MatStack_Error("Singular matrix in MInvers."); */
  3997. return TCL_ERROR;
  3998. }
  3999.  
  4000. r[AFFINE_IDX_0_0] = d00/D; r[AFFINE_IDX_0_1] = -d10/D; r[AFFINE_IDX_0_2] = d20/D; r[AFFINE_IDX_0_3] = -d30/D;
  4001. r[AFFINE_IDX_1_0] = -d01/D; r[AFFINE_IDX_1_1] = d11/D; r[AFFINE_IDX_1_2] = -d21/D; r[AFFINE_IDX_1_3] = d31/D;
  4002. r[AFFINE_IDX_2_0] = d02/D; r[AFFINE_IDX_2_1] = -d12/D; r[AFFINE_IDX_2_2] = d22/D; r[AFFINE_IDX_2_3] = -d32/D;
  4003. r[AFFINE_IDX_3_0] = -d03/D; r[AFFINE_IDX_3_1] = d13/D; r[AFFINE_IDX_3_2] = -d23/D; r[AFFINE_IDX_3_3] = d33/D;
  4004. return TCL_OK;
  4005. }
  4006. /* Odie_Affine_From_Normal */
  4007. static void Odie_Affine_From_Normal(AFFINE RESULT,VectorXYZ NORMAL){
  4008. double c,s,C;
  4009. VectorXYZ axis;
  4010.  
  4011. /* If UP and NORMAL are identical (or nearly identical) no rotation */
  4012. if (VectorXYZ_IsZero(NORMAL)) {
  4013. Odie_Affine4x4_Identity(RESULT);
  4014. return;
  4015. }
  4016.  
  4017. if (VectorXYZ_SamePoint(Odie_Up_Direction,NORMAL)) {
  4018. Odie_Affine4x4_Identity(RESULT);
  4019. return;
  4020. }
  4021. VectorXYZ_Cross_Product(axis,Odie_Up_Direction,NORMAL);
  4022. VectorXYZ_Normalize(axis);
  4023. c=VectorXYZ_Dot_Product(Odie_Up_Direction,NORMAL);
  4024. s=sqrt(1-c*c);
  4025. C=1-c;
  4026. RESULT[AFFINE_IDX_0_0]=axis[X_IDX]*axis[X_IDX]*C+c;
  4027. RESULT[AFFINE_IDX_0_1]=axis[X_IDX]*axis[Y_IDX]*C-axis[Z_IDX]*s;
  4028. RESULT[AFFINE_IDX_0_2]=axis[X_IDX]*axis[Z_IDX]*C+axis[Y_IDX]*s;
  4029. RESULT[AFFINE_IDX_0_3]=0.0;
  4030.  
  4031. RESULT[AFFINE_IDX_1_0]=axis[Y_IDX]*axis[X_IDX]*C+axis[Z_IDX]*s;
  4032. RESULT[AFFINE_IDX_1_1]=axis[Y_IDX]*axis[Y_IDX]*C+c;
  4033. RESULT[AFFINE_IDX_1_2]=axis[Y_IDX]*axis[Z_IDX]*C-axis[X_IDX]*s;
  4034. RESULT[AFFINE_IDX_1_3]=0.0;
  4035.  
  4036. RESULT[AFFINE_IDX_2_0]=axis[Z_IDX]*axis[X_IDX]*C-axis[Y_IDX]*s;
  4037. RESULT[AFFINE_IDX_2_1]=axis[Z_IDX]*axis[Y_IDX]*C+axis[X_IDX]*s;
  4038. RESULT[AFFINE_IDX_2_2]=axis[Z_IDX]*axis[Z_IDX]*C+c;
  4039. RESULT[AFFINE_IDX_2_3]=0.0;
  4040.  
  4041. RESULT[AFFINE_IDX_3_0]=0.0;
  4042. RESULT[AFFINE_IDX_3_1]=0.0;
  4043. RESULT[AFFINE_IDX_3_2]=0.0;
  4044. RESULT[AFFINE_IDX_3_3]=1.0;
  4045.  
  4046. }
  4047. /* VectorXY_BBOX_Copy */
  4048. static inline void VectorXY_BBOX_Copy(BBOXXY dest,BBOXXY src){ dest[BBOX_X0_IDX]=src[BBOX_X0_IDX];
  4049. dest[BBOX_Y1_IDX]=src[BBOX_Y1_IDX];
  4050. dest[BBOX_X1_IDX]=src[BBOX_X1_IDX];
  4051. dest[BBOX_X1_IDX]=src[BBOX_X1_IDX];
  4052. }
  4053. /* VectorXY_BBOX_Reset */
  4054. static inline void VectorXY_BBOX_Reset(BBOXXY R){
  4055. R[BBOX_X0_IDX]=R[BBOX_Y0_IDX]=1e99;
  4056. R[BBOX_Y1_IDX]=R[BBOX_X1_IDX]=-1e99;
  4057. }
  4058. /* VectorXY_IsBetween_BBOX */
  4059. static inline int VectorXY_IsBetween_BBOX(VectorXY POINT,VectorXY A,VectorXY B){
  4060. if (POINT[X_IDX]<A[X_IDX] && POINT[X_IDX]<B[X_IDX]) return 0;
  4061. if (POINT[X_IDX]>A[X_IDX] && POINT[X_IDX]>B[X_IDX]) return 0;
  4062. if (POINT[Y_IDX]<A[Y_IDX] && POINT[Y_IDX]<B[Y_IDX]) return 0;
  4063. if (POINT[Y_IDX]>A[Y_IDX] && POINT[Y_IDX]>B[Y_IDX]) return 0;
  4064. return 1;
  4065. }
  4066. /* VectorXY_Within_BBOX */
  4067. static inline int VectorXY_Within_BBOX(VectorXY POINT,BBOXXY bbox){
  4068. if(POINT[X_IDX]<bbox[BBOX_X0_IDX]) return 0;
  4069. if(POINT[Y_IDX]>bbox[BBOX_Y1_IDX]) return 0;
  4070. if(POINT[X_IDX]>bbox[BBOX_X1_IDX]) return 0;
  4071. if(POINT[Y_IDX]<bbox[BBOX_Y0_IDX]) return 0;
  4072. return 1;
  4073. }
  4074. /* XY_Within_BBOX */
  4075. static inline int XY_Within_BBOX(double x, double y,BBOXXY bbox){
  4076. if(x<bbox[BBOX_X0_IDX]) return 0;
  4077. if(y>bbox[BBOX_Y1_IDX]) return 0;
  4078. if(x>bbox[BBOX_X1_IDX]) return 0;
  4079. if(y<bbox[BBOX_Y0_IDX]) return 0;
  4080. return 1;
  4081. }
  4082. /* VectorXY_BBOX_Measure */
  4083. static inline void VectorXY_BBOX_Measure(VectorXY POINT,BBOXXY bbox){
  4084. if(POINT[X_IDX]<bbox[BBOX_X0_IDX]) bbox[BBOX_X0_IDX]=POINT[X_IDX];
  4085. if(POINT[Y_IDX]>bbox[BBOX_Y1_IDX]) bbox[BBOX_Y1_IDX]=POINT[Y_IDX];
  4086. if(POINT[X_IDX]>bbox[BBOX_X1_IDX]) bbox[BBOX_X1_IDX]=POINT[X_IDX];
  4087. if(POINT[Y_IDX]<bbox[BBOX_Y0_IDX]) bbox[BBOX_Y0_IDX]=POINT[Y_IDX];
  4088. }
  4089. /* BBOX_BBOX_Intersect */
  4090. static inline int BBOX_BBOX_Intersect(BBOXXY A,BBOXXY B){
  4091. int a_inside_b=0;
  4092. int b_inside_a=0;
  4093. int i,j;
  4094. if(A[BBOX_X0_IDX]>=B[BBOX_X0_IDX] && A[BBOX_X1_IDX]<=B[BBOX_X1_IDX]) {
  4095. if(A[BBOX_Y1_IDX]<=B[BBOX_Y1_IDX] && A[BBOX_Y0_IDX]>=B[BBOX_Y0_IDX]) {
  4096. a_inside_b=1;
  4097. }
  4098. }
  4099. if(B[BBOX_X0_IDX]>=A[BBOX_X0_IDX] && B[BBOX_X1_IDX]<=A[BBOX_X1_IDX]) {
  4100. if(B[BBOX_Y1_IDX]<=A[BBOX_Y1_IDX] && B[BBOX_Y0_IDX]>=A[BBOX_Y0_IDX]) {
  4101. b_inside_a=1;
  4102. }
  4103. }
  4104. if(a_inside_b && b_inside_a) {
  4105. return 2;
  4106. }
  4107. if(a_inside_b) {
  4108. return 3;
  4109. }
  4110. if(b_inside_a) {
  4111. return 4;
  4112. }
  4113. if(XY_Within_BBOX(B[BBOX_X0_IDX],B[BBOX_Y1_IDX],A)) return 1;
  4114. if(XY_Within_BBOX(B[BBOX_X0_IDX],B[BBOX_Y0_IDX],A)) return 1;
  4115. if(XY_Within_BBOX(B[BBOX_X1_IDX],B[BBOX_Y1_IDX],A)) return 1;
  4116. if(XY_Within_BBOX(B[BBOX_X1_IDX],B[BBOX_Y0_IDX],A)) return 1;
  4117. if(XY_Within_BBOX(A[BBOX_X0_IDX],A[BBOX_Y1_IDX],B)) return 1;
  4118. if(XY_Within_BBOX(A[BBOX_X0_IDX],A[BBOX_Y0_IDX],B)) return 1;
  4119. if(XY_Within_BBOX(A[BBOX_X1_IDX],A[BBOX_Y1_IDX],B)) return 1;
  4120. if(XY_Within_BBOX(A[BBOX_X1_IDX],A[BBOX_Y0_IDX],B)) return 1;
  4121. return 0;
  4122. }
  4123. /* *Matrix_To_quaternion */
  4124. const char *Matrix_To_quaternion(Odie_MatrixObj *matrix,int form){
  4125. if(matrix->form==form) {
  4126. return NULL;
  4127. }
  4128. if(Matrix_To_cartesian(matrix,MATFORM_cartesian)) {
  4129. return "Cannot convert to spherical";
  4130. }
  4131. if(matrix->form==MATFORM_cartesian) {
  4132. odiemath_cartesian_to_spherical(matrix->matrix,matrix->matrix);
  4133. }
  4134. matrix->form=form;
  4135. matrix->rows=4;
  4136. matrix->cols=1;
  4137. return NULL;
  4138. }
  4139. /* *Quaternion_To_TclObj */
  4140. Tcl_Obj *Quaternion_To_TclObj(QUATERNION R){
  4141. Odie_MatrixObj *RESULT;
  4142. RESULT=Odie_MatrixObj_Create(MATFORM_quaternion);
  4143. RESULT->matrix[QW_IDX]=R[QW_IDX];
  4144. RESULT->matrix[QX_IDX]=R[QX_IDX];
  4145. RESULT->matrix[QY_IDX]=R[QY_IDX];
  4146. RESULT->matrix[QZ_IDX]=R[QZ_IDX];
  4147. return Matrix_To_TclObj(RESULT);
  4148. }
  4149. /* Odie_GetQuaternionFromTclObj */
  4150. int Odie_GetQuaternionFromTclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,QUATERNION R){
  4151. Tcl_Obj **elemPtrs;
  4152. int cols,i;
  4153. if(objPtr->typePtr) {
  4154. if(objPtr->typePtr->setFromAnyProc==&MatrixObj_setFromAnyProc) {
  4155. /*
  4156. ** Object is a matrix
  4157. */
  4158. const char *err;
  4159. Odie_MatrixObj *value=objPtr->internalRep.otherValuePtr;
  4160. err=Matrix_To_cartesian(value,MATFORM_quaternion);
  4161. if(err) {
  4162. Tcl_AppendResult(interp,err,NULL);
  4163. return TCL_ERROR;
  4164. }
  4165. R[QW_IDX]=value->matrix[QW_IDX];
  4166. R[QX_IDX]=value->matrix[QX_IDX];
  4167. R[QY_IDX]=value->matrix[QY_IDX];
  4168. R[QZ_IDX]=value->matrix[QZ_IDX];
  4169. return TCL_OK;
  4170. }
  4171. }
  4172.  
  4173. /* Step one, Measure the matrix */
  4174. if(Tcl_ListObjGetElements(interp, objPtr, &cols, &elemPtrs)) return TCL_ERROR;
  4175. if(cols<4) {
  4176. Tcl_SetObjResult(interp,Tcl_NewStringObj("Needs 3 columns",-1));
  4177. return TCL_ERROR;
  4178. }
  4179. for(i=0;i<4;i++) {
  4180. double temp;
  4181. if(Tcl_GetDoubleFromObj(interp, elemPtrs[i], &temp)) return TCL_ERROR;
  4182. R[i]=temp;
  4183. }
  4184. return TCL_OK;
  4185. }
  4186. /* Quaternion_Add */
  4187. void Quaternion_Add(QUATERNION r, QUATERNION p, QUATERNION q){
  4188. r[QW_IDX]=p[QW_IDX]+q[QW_IDX];
  4189. r[QX_IDX]=p[QX_IDX]+q[QX_IDX];
  4190. r[QY_IDX]=p[QY_IDX]+q[QY_IDX];
  4191. r[QZ_IDX]=p[QZ_IDX]+q[QZ_IDX];
  4192. }
  4193. /* Quaternion_Subtract */
  4194. void Quaternion_Subtract(QUATERNION r, QUATERNION p, QUATERNION q){
  4195. r[QW_IDX]=p[QW_IDX]-q[QW_IDX];
  4196. r[QX_IDX]=p[QX_IDX]-q[QX_IDX];
  4197. r[QY_IDX]=p[QY_IDX]-q[QY_IDX];
  4198. r[QZ_IDX]=p[QZ_IDX]-q[QZ_IDX];
  4199. }
  4200. /* Quaternion_Multiply */
  4201. void Quaternion_Multiply(QUATERNION r, QUATERNION p, QUATERNION q){
  4202. double t0, t1, t2;
  4203.  
  4204. t0 = p[QW_IDX] * q[QW_IDX] - p[QX_IDX] * q[QX_IDX] - p[QY_IDX] * q[QY_IDX] - p[QZ_IDX] * q[QZ_IDX];
  4205. t1 = p[QW_IDX] * q[QX_IDX] + p[QX_IDX] * q[QW_IDX] + p[QY_IDX] * q[QZ_IDX] - p[QZ_IDX] * q[QY_IDX];
  4206. t2 = p[QW_IDX] * q[QY_IDX] + p[QY_IDX] * q[QW_IDX] + p[QZ_IDX] * q[QX_IDX] - p[QX_IDX] * q[QZ_IDX];
  4207. r[QZ_IDX] = p[QW_IDX] * q[QZ_IDX] + p[QZ_IDX] * q[QW_IDX] + p[QX_IDX] * q[QY_IDX] - p[QY_IDX] * q[QX_IDX];
  4208. r[QW_IDX] = t0;
  4209. r[QX_IDX] = t1;
  4210. r[QY_IDX] = t2;
  4211. }
  4212. /* Quaternion_Divide */
  4213. void Quaternion_Divide(QUATERNION r, QUATERNION p, QUATERNION q){
  4214. QUATERNION Q,t,s;
  4215. double a;
  4216. Q[QW_IDX]=q[QW_IDX];
  4217. Q[QX_IDX]=-q[QX_IDX];
  4218. Q[QY_IDX]=-q[QY_IDX];
  4219. Q[QZ_IDX]=-q[QZ_IDX];
  4220. Quaternion_Multiply(t,p,Q);
  4221. Quaternion_Multiply(s,Q,Q);
  4222. a=1.0/s[QW_IDX];
  4223. r[QW_IDX]=t[QW_IDX]*a;
  4224. r[QX_IDX]=t[QX_IDX]*a;
  4225. r[QY_IDX]=t[QY_IDX]*a;
  4226. r[QZ_IDX]=t[QY_IDX]*a;
  4227. }
  4228. /* Quaternion_Square_Root */
  4229. void Quaternion_Square_Root(QUATERNION s, QUATERNION q){
  4230. double len,m;
  4231. double a,b;
  4232. QUATERNION r;
  4233.  
  4234. len=sqrt(q[QW_IDX]*q[QW_IDX]+q[QX_IDX]*q[QX_IDX]+q[QY_IDX]*q[QY_IDX]);
  4235. if(len==0) {
  4236. s[QW_IDX]=s[QX_IDX]=s[QY_IDX]=s[QZ_IDX]=0.0;
  4237. return;
  4238. }
  4239. r[QW_IDX]=q[QW_IDX]*1.0;
  4240. r[QX_IDX]=q[QX_IDX]*1.0;
  4241. r[QY_IDX]=q[QY_IDX]*1.0;
  4242. r[QZ_IDX]=0.0;
  4243. m=1.0/sqrt(r[QW_IDX]*r[QW_IDX]+r[QX_IDX]*r[QX_IDX]);
  4244. a=sqrt((1.0+r[QY_IDX])*0.5);
  4245. b=sqrt((1.0-r[QY_IDX])*0.5);
  4246. s[QW_IDX]=sqrt(len)*b*r[QW_IDX]*m;
  4247. s[QX_IDX]=sqrt(len)*b*r[QX_IDX]*m;
  4248. s[QY_IDX]=sqrt(len)*a;
  4249. s[QZ_IDX]=q[QZ_IDX];
  4250. }
  4251. /* Quaternion_Square */
  4252. void Quaternion_Square(QUATERNION r, QUATERNION q){
  4253. double a;
  4254. a=2.0*q[QW_IDX];
  4255. r[QW_IDX]=q[QW_IDX]*q[QW_IDX]-q[QX_IDX]*q[QX_IDX]-q[QY_IDX]*q[QY_IDX]-q[QZ_IDX]*q[QZ_IDX];
  4256. r[QX_IDX]=a*q[QX_IDX];
  4257. r[QY_IDX]=a*q[QY_IDX];
  4258. r[QZ_IDX]=a*q[QZ_IDX];
  4259. }
  4260. /* EulerRotation_To_Quaternion */
  4261. void EulerRotation_To_Quaternion(QUATERNION q,double heading, double attitude, double bank){
  4262. // Assuming the angles are in radians.
  4263. double c1 = cos(heading*0.5);
  4264. double s1 = sin(heading*0.5);
  4265. double c2 = cos(attitude*0.5);
  4266. double s2 = sin(attitude*0.5);
  4267. double c3 = cos(bank*0.5);
  4268. double s3 = sin(bank*0.5);
  4269. double c1c2 = c1*c2;
  4270. double s1s2 = s1*s2;
  4271. q[QW_IDX] =c1c2*c3 - s1s2*s3;
  4272. q[QX_IDX] =c1c2*s3 + s1s2*c3;
  4273. q[QY_IDX] =s1*c2*c3 + c1*s2*s3;
  4274. q[QZ_IDX] =c1*s2*c3 - s1*c2*s3;
  4275. }
  4276. /* VectorXYZ_Rotate_by_Quaternion */
  4277. void VectorXYZ_Rotate_by_Quaternion(VECTORXYZ r, QUATERNION p, VECTORXYZ A){
  4278. double w=p[QW_IDX]; // real part of quaternion
  4279. double x=p[QX_IDX]; // imaginary i part of quaternion
  4280. double y=p[QY_IDX]; // imaginary j part of quaternion
  4281. double z=p[QZ_IDX]; // imaginary k part of quaternion
  4282. double px=A[X_IDX];
  4283. double py=A[Y_IDX];
  4284. double pz=A[Z_IDX];
  4285. r[X_IDX] = w*w*px + 2*y*w*pz - 2*z*w*py + x*x*px + 2*y*x*py + 2*z*x*pz - z*z*px - y*y*px;
  4286. r[Y_IDX] = 2*x*y*px + y*y*py + 2*z*y*pz + 2*w*z*px - z*z*py + w*w*py - 2*x*w*pz - x*x*py;
  4287. r[Z_IDX] = 2*x*z*px + 2*y*z*py + z*z*pz - 2*w*y*px - y*y*pz + 2*w*x*py - x*x*pz + w*w*pz;
  4288. }
  4289. /* Quaternion_To_EulerRotation */
  4290. void Quaternion_To_EulerRotation (VECTORXYZ r, QUATERNION p){
  4291. double sqw = p[QW_IDX]*p[QW_IDX];
  4292. double sqx = p[QX_IDX]*p[QX_IDX];
  4293. double sqy = p[QY_IDX]*p[QY_IDX];
  4294. double sqz = p[QZ_IDX]*p[QZ_IDX];
  4295. double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
  4296. double test = p[QX_IDX]*p[QY_IDX] + p[QZ_IDX]*p[QW_IDX];
  4297.  
  4298. if (test > 0.499*unit) { // singularity at north pole
  4299. r[EULER_HEADING] = 2 * atan2(p[QX_IDX],p[QW_IDX]);
  4300. r[EULER_ATTITUDE] = M_PI*0.5;
  4301. r[EULER_BANK] = 0;
  4302. return;
  4303. }
  4304. if (test < -0.499*unit) { // singularity at south pole
  4305. r[EULER_HEADING] = -2 * atan2(p[QX_IDX],p[QW_IDX]);
  4306. r[EULER_ATTITUDE] = M_PI*-0.5;
  4307. r[EULER_BANK] = 0;
  4308. return;
  4309. }
  4310. r[EULER_HEADING] = atan2(2*p[QY_IDX]*p[QW_IDX]-2*p[QX_IDX]*p[QZ_IDX] , sqx - sqy - sqz + sqw);
  4311. r[EULER_ATTITUDE] = asin(2*test/unit);
  4312. r[EULER_BANK] = atan2(2*p[QX_IDX]*p[QW_IDX]-2*p[QY_IDX]*p[QZ_IDX] , -sqx + sqy - sqz + sqw);
  4313. }
  4314. /* Quaternion_From_Normal */
  4315. static inline void Quaternion_From_Normal(QUATERNION RESULT,VectorXYZ from,VectorXYZ to){
  4316. VectorXYZ H;
  4317. VectorXYZ_Add(H,from,to);
  4318. /* Special case?
  4319. if(VectorXYZ_IsZero(H)) {
  4320. RESULT[QW_IDX]=0.0;
  4321. RESULT[QX_IDX]=1.0;
  4322. RESULT[QY_IDX]=0.0;
  4323. RESULT[QZ_IDX]=0.0;
  4324. }
  4325. */
  4326. VectorXYZ_Normalize(H);
  4327. RESULT[QW_IDX]=VectorXYZ_Dot_Product(from,H);
  4328. RESULT[QX_IDX]=from[Y_IDX]*H[Z_IDX] - from[Z_IDX]*H[Y_IDX];
  4329. RESULT[QY_IDX]=from[Z_IDX]*H[X_IDX] - from[X_IDX]*H[Z_IDX];
  4330. RESULT[QZ_IDX]=from[X_IDX]*H[Y_IDX] - from[Y_IDX]*H[X_IDX];
  4331. }
  4332. /* *Odie_Matrix_To_Fit */
  4333. static Odie_MatrixObj *Odie_Matrix_To_Fit(Odie_MatrixObj *A,Odie_MatrixObj *B){
  4334. Odie_MatrixObj *C;
  4335. int size_a;
  4336. int size_b;
  4337. if(A->rows==B->rows && A->cols==B->cols) {
  4338. if(A->form && A->form==B->form) {
  4339. C=Odie_MatrixObj_Create(A->form);
  4340. } else {
  4341. C=Odie_MatrixObj_Create_NXN(A->rows,A->cols);
  4342. }
  4343. return C;
  4344. }
  4345. size_a=A->rows*A->cols;
  4346. size_b=B->rows*B->cols;
  4347. if(size_a<size_b) {
  4348. C=Odie_MatrixObj_Create_NXN(size_b,1);
  4349. } else {
  4350. C=Odie_MatrixObj_Create_NXN(size_a,1);
  4351. }
  4352. return C;
  4353. }
  4354. /* Vector_GridScaler */
  4355. static inline double Vector_GridScaler(double x,double grid,double grain){
  4356. double q;
  4357. q=grid*round(x/grid);
  4358. if((x-q)>grain) {
  4359. q+=grain;
  4360. }
  4361. return q;
  4362. }
  4363. /* Vector2d_SamePoint */
  4364. inline extern int Vector2d_SamePoint(double x0, double y0, double x1, double y1){
  4365. /*
  4366. ** Return TRUE if x0,y0 is the same point as x1,y1
  4367. */
  4368. return floatCompare(x0,x1)==0 && floatCompare(y0,y1)==0;
  4369. }
  4370. /* Vector2d_IsColinear */
  4371. inline extern int Vector2d_IsColinear(double x1,double y1,double x2,double y2,double x3,double y3){
  4372. /* Detect of two lines are colinear */
  4373. double c=(x3-x1)*(y2-y1)-(y3-y1)*(x2-x1);
  4374. if(fabs(c) < __FLT_EPSILON__) return 1;
  4375. return 0;
  4376. }
  4377. /* Vector2d_LineLineCoincident */
  4378. inline extern int Vector2d_LineLineCoincident(
  4379. double ax1, double ay1,
  4380. double ax2, double ay2,
  4381. double bx1, double by1,
  4382. double bx2, double by2){
  4383. double x,y;
  4384. int c=0;
  4385. /* Check if wall completely wraps other wall */
  4386. if(Vector2d_SamePoint(ax1,ay1,bx1,by1)) {
  4387. if(Vector2d_SamePoint(ax2,ay2,bx2,by2)) return 6;
  4388. if(Vector2d_PointIsOnSegment(ax2,ay2,bx1,by1,bx2,by2)) return 2;
  4389. return 0;
  4390. }
  4391. if(Vector2d_SamePoint(ax2,ay2,bx1,by1)) {
  4392. if(Vector2d_SamePoint(ax1,ay1,bx2,by2)) return 6;
  4393. if(Vector2d_PointIsOnSegment(ax1,ay1,bx1,by1,bx2,by2)) return 4;
  4394. return 0;
  4395. }
  4396. if(Vector2d_SamePoint(ax1,ay1,bx2,by2)) {
  4397. if(Vector2d_PointIsOnSegment(ax2,ay2,bx1,by1,bx2,by2)) return 2;
  4398. return 0;
  4399. }
  4400. if(Vector2d_SamePoint(ax2,ay2,bx2,by2)) {
  4401. if(Vector2d_PointIsOnSegment(ax1,ay1,bx1,by1,bx2,by2)) return 4;
  4402. return 0;
  4403. }
  4404. c=ODIE_Math_LineLineIntersect(ax1,ay1,ax2,ay2,bx1,by1,bx2,by2,&x,&y);
  4405. if(c) {
  4406. if(Vector2d_SamePoint(ax1,ay1,x,y)) {
  4407. return 0;
  4408. }
  4409. if(Vector2d_SamePoint(ax2,ay2,x,y)) {
  4410. return 0;
  4411. }
  4412. }
  4413. return c;
  4414. }
  4415. /* ODIE_Math_LineLineIntersect */
  4416. int ODIE_Math_LineLineIntersect(
  4417. double ax1, double ay1,
  4418. double ax2, double ay2,
  4419. double bx1, double by1,
  4420. double bx2, double by2,
  4421. double *x, double *y){
  4422. /*
  4423. ** Detect the intersection of two lines
  4424. ** Adapted from: http://paulbourke.net/geometry/lineline2d/pdb.c
  4425. */
  4426. double mua,mub;
  4427. double denom,numera,numerb;
  4428.  
  4429.  
  4430.  
  4431. denom = (by2-by1) * (ax2-ax1) - (bx2-bx1) * (ay2-ay1);
  4432. numera = (bx2-bx1) * (ay1-by1) - (by2-by1) * (ax1-bx1);
  4433. numerb = (ax2-ax1) * (ay1-by1) - (ay2-ay1) * (ax1-bx1);
  4434.  
  4435. /* Are the line parallel */
  4436. if (ODIE_Real_Is_Zero(denom)) {
  4437. if (ODIE_Real_Is_Zero(numera) && ODIE_Real_Is_Zero(numerb)) {
  4438. /* Are the line coincident? */
  4439. int within=1;
  4440. if(ax2>ax1) {
  4441. if(bx1>ax2 && bx2>ax2) {
  4442. within=0;
  4443. } else if(bx1<ax1 && bx2<ax1) {
  4444. within=0;
  4445. }
  4446. } else {
  4447. if(bx1>ax1 && bx2>ax1) {
  4448. within=0;
  4449. } else if(bx1<ax2 && bx2<ax2) {
  4450. within=0;
  4451. }
  4452. }
  4453. if(ay2>ay1) {
  4454. if(by1>ay2 && by2>ay2) {
  4455. within=0;
  4456. } else if(by1<ay1 && by2<ay1) {
  4457. within=0;
  4458. }
  4459. } else {
  4460. if(by1>ay1 && by2>ay1) {
  4461. within=0;
  4462. } else if(by1<ay2 && by2<ay2) {
  4463. within=0;
  4464. }
  4465. }
  4466. if(within) {
  4467. *x = (ax1 + ax2) / 2;
  4468. *y = (ay1 + ay2) / 2;
  4469. return(2);
  4470. }
  4471. }
  4472. *x = 0;
  4473. *y = 0;
  4474. return(0);
  4475. }
  4476.  
  4477. /* Is the intersection along the the segments */
  4478. mua = numera / denom;
  4479. mub = numerb / denom;
  4480. if (mua < 0 || mua > 1 || mub < 0 || mub > 1) {
  4481. *x = 0;
  4482. *y = 0;
  4483. return(0);
  4484. }
  4485. *x = ax1 + mua * (ax2 - ax1);
  4486. *y = ay1 + mua * (ay2 - ay1);
  4487. return(1);
  4488. }
  4489. /* Vector2d_PointIsOnSegment */
  4490. static inline int Vector2d_PointIsOnSegment(double x,double y,double x1,double y1,double x2,double y2){
  4491. /* Returns:
  4492. ** 0 - not on segment
  4493. ** 1 - along segment
  4494. ** 2 - endpoint of segment
  4495. */
  4496. /* Bounding box check */
  4497. if(x1>x2) {
  4498. if(x>(x1+OdieGrain)) return 0;
  4499. if(x<(x2-OdieGrain)) return 0;
  4500. } else {
  4501. if(x>(x2+OdieGrain)) return 0;
  4502. if(x<(x1-OdieGrain)) return 0;
  4503. }
  4504. if(y1>y2) {
  4505. if(y>(y1+OdieGrain)) return 0;
  4506. if(y<(y2-OdieGrain)) return 0;
  4507. } else {
  4508. if(y>(y2+OdieGrain)) return 0;
  4509. if(y<(y1-OdieGrain)) return 0;
  4510. }
  4511. if(Vector2d_SamePoint(x,y,x1,y1)) return 2;
  4512. if(Vector2d_SamePoint(x,y,x2,y2)) return 2;
  4513.  
  4514. /* Detect of two lines are colinear */
  4515. if (Vector2d_IsColinear(x,y,x1,y1,x2,y2)) {
  4516. return 1;
  4517. }
  4518. return 0;
  4519. }
  4520. /* ODIE_Math_LineCircleIntersect */
  4521. int ODIE_Math_LineCircleIntersect(
  4522. double p1_x, double p1_y,
  4523. double p2_x, double p2_y,
  4524. double sc_x, double sc_y,
  4525. double r,
  4526. double *mu1, double *mu2){
  4527. /*
  4528. ** Detect the intersection of a line and a circle
  4529. ** Adapted from: http://http://paulbourke.net/geometry/circlesphere/raysphere.c
  4530. */
  4531. double a,b,c;
  4532. double bb4ac;
  4533. double dp_x,dp_y;
  4534. *mu1 = 0;
  4535. *mu2 = 0;
  4536.  
  4537. dp_x = p2_x - p1_x;
  4538. dp_y = p2_y - p1_y;
  4539. a = dp_x * dp_x + dp_y * dp_y;
  4540. b = 2 * (dp_x * (p1_x - sc_x) + dp_y * (p1_y - sc_y));
  4541. c = sc_x * sc_x + sc_y * sc_y;
  4542. c += p1_x * p1_x + p1_y * p1_y;
  4543. c -= 2 * (sc_x * p1_x + sc_y * p1_y);
  4544. c -= r * r;
  4545. bb4ac = b * b - 4 * a * c;
  4546. if (ODIE_Real_Is_Zero(a) || bb4ac < 0) {
  4547. return(0);
  4548. }
  4549.  
  4550. *mu1 = (-b + sqrt(bb4ac)) / (2 * a);
  4551. *mu2 = (-b - sqrt(bb4ac)) / (2 * a);
  4552.  
  4553. return(1);
  4554. }
  4555. /* Vector3d_SamePoint */
  4556. inline extern int Vector3d_SamePoint(double x0, double y0, double z0, double x1, double y1, double z1){
  4557. /*
  4558. ** Return TRUE if x0,y0 is the same point as x1,y1
  4559. */
  4560. return floatCompare(x0,x1)==0 && floatCompare(y0,y1)==0 && floatCompare(z0,z1)==0;
  4561. }
  4562. /* odiemath_polar_to_vec2 */
  4563. void odiemath_polar_to_vec2(VECTORXY A,VECTORXY R){
  4564. /*
  4565. ** Make a copy of the input matrix in case we are outputing back
  4566. ** to the same pointer
  4567. */
  4568. double radius,theta;
  4569. radius=A[RADIUS];
  4570. theta=A[THETA];
  4571. R[X_IDX]=radius*cos(theta);
  4572. R[Y_IDX]=radius*sin(theta);
  4573. }
  4574. /* odiemath_vec2_to_polar */
  4575. void odiemath_vec2_to_polar(VECTORXY A,VECTORXY R){
  4576. double x,y;
  4577. x=A[X_IDX];
  4578. y=A[Y_IDX];
  4579. R[RADIUS]=sqrt(x*x + y*y);
  4580. R[THETA] =atan2(y,x);
  4581. }
  4582. /* *Matrix_To_vector_xy */
  4583. const char *Matrix_To_vector_xy(Odie_MatrixObj *matrix,int form){
  4584. if(matrix->form==form) {
  4585. return NULL;
  4586. }
  4587. switch(matrix->form) {
  4588. case MATFORM_vector_xy:
  4589. return TCL_OK;
  4590. case MATFORM_vector_xyz: {
  4591. return NULL;
  4592. }
  4593. case MATFORM_cylindrical: {
  4594. odiemath_vec2_to_polar(matrix->matrix,matrix->matrix);
  4595. matrix->form=MATFORM_cartesian;
  4596. return NULL;
  4597. }
  4598. }
  4599. return Matrix_To_cartesian(matrix,MATFORM_vector_xy);
  4600. }
  4601. /* *VectorXY_To_TclObj */
  4602. Tcl_Obj *VectorXY_To_TclObj(VectorXY R){
  4603. Odie_MatrixObj *RESULT;
  4604. RESULT=Odie_MatrixObj_Create(MATFORM_vector_xy);
  4605. RESULT->matrix[X_IDX]=R[X_IDX];
  4606. RESULT->matrix[Y_IDX]=R[Y_IDX];
  4607. return Matrix_To_TclObj(RESULT);
  4608. }
  4609. /* Odie_GetVectorXYFromTclObj */
  4610. int Odie_GetVectorXYFromTclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,VectorXY R){
  4611. Tcl_Obj **elemPtrs;
  4612. int cols,i;
  4613. if(objPtr->typePtr) {
  4614. if(objPtr->typePtr->setFromAnyProc==&MatrixObj_setFromAnyProc) {
  4615. /*
  4616. ** Object is a matrix
  4617. */
  4618. const char *err;
  4619. Odie_MatrixObj *value=objPtr->internalRep.otherValuePtr;
  4620. err=Matrix_To_cartesian(value,MATFORM_vector_xy);
  4621. if(err) {
  4622. Tcl_AppendResult(interp,err,NULL);
  4623. return TCL_ERROR;
  4624. }
  4625. R[X_IDX]=value->matrix[X_IDX];
  4626. R[Y_IDX]=value->matrix[Y_IDX];
  4627. return TCL_OK;
  4628. }
  4629. }
  4630.  
  4631. /* Step one, Measure the matrix */
  4632. if(Tcl_ListObjGetElements(interp, objPtr, &cols, &elemPtrs)) return TCL_ERROR;
  4633. for(i=0;i<2;i++) {
  4634. double temp;
  4635. if(cols<=i) {
  4636. R[i]=0.0;
  4637. } else {
  4638. if(Tcl_GetDoubleFromObj(interp, elemPtrs[i], &temp)) return TCL_ERROR;
  4639. R[i]=temp;
  4640. }
  4641. }
  4642. return TCL_OK;
  4643. }
  4644. /* VectorXY_GridAlign */
  4645. static inline void VectorXY_GridAlign(VECTORXYZ A,double grid){
  4646. double x,q,grain;
  4647. grain=grid*0.5;
  4648. if(grid<=0) return;
  4649. A[X_IDX]=Vector_GridScaler(A[X_IDX],grid,grain);
  4650. A[Y_IDX]=Vector_GridScaler(A[Y_IDX],grid,grain);
  4651. }
  4652. /* VectorXY_SamePoint */
  4653. inline extern int VectorXY_SamePoint(VectorXY A, VectorXY B){
  4654. if(fabs(B[X_IDX]-A[X_IDX])>Vector_Tolerance) return 0;
  4655. if(fabs(B[Y_IDX]-A[Y_IDX])>Vector_Tolerance) return 0;
  4656. return 1;
  4657. }
  4658. /* VectorXY_SameGridPoint */
  4659. inline extern int VectorXY_SameGridPoint(VectorXY A, VectorXY B,double grid){
  4660. if(fabs(B[X_IDX]-A[X_IDX])>grid) return 0;
  4661. if(fabs(B[Y_IDX]-A[Y_IDX])>grid) return 0;
  4662. return 1;
  4663. }
  4664. /* VectorXY_Add */
  4665. inline extern void VectorXY_Add(VECTORXY C,VECTORXY A,VECTORXY B){
  4666. C[X_IDX]=B[X_IDX]+A[X_IDX];
  4667. C[Y_IDX]=B[Y_IDX]+A[Y_IDX];
  4668. }
  4669. /* VectorXY_Subtract */
  4670. inline extern void VectorXY_Subtract(VECTORXY C,VECTORXY A,VECTORXY B){
  4671. C[X_IDX]=A[X_IDX]-B[X_IDX];
  4672. C[Y_IDX]=A[Y_IDX]-B[Y_IDX];
  4673. }
  4674. /* VectorXY_Midpoint */
  4675. static inline void VectorXY_Midpoint(VECTORXY C,VECTORXY A,VECTORXY B){
  4676. C[X_IDX]=(B[X_IDX]-A[X_IDX])*0.5+A[X_IDX];
  4677. C[Y_IDX]=(B[Y_IDX]-A[Y_IDX])*0.5+A[Y_IDX];
  4678. }
  4679. /* VectorXY_Normalize */
  4680. inline extern void VectorXY_Normalize(VECTORXY A){
  4681. double length=sqrt(A[X_IDX]*A[X_IDX]+A[Y_IDX]*A[Y_IDX]);
  4682. if(length < __FLT_EPSILON__ ) {
  4683. return;
  4684. }
  4685. A[X_IDX]/=length;
  4686. A[Y_IDX]/=length;
  4687. }
  4688. /* VectorXY_Round */
  4689. inline extern void VectorXY_Round(VECTORXY A){
  4690. A[X_IDX]=round(A[X_IDX]);
  4691. A[Y_IDX]=round(A[Y_IDX]);
  4692. }
  4693. /* VectorXY_Set */
  4694. inline extern void VectorXY_Set(VECTORXY A,VECTORXY B){
  4695. A[X_IDX]=B[X_IDX];
  4696. A[Y_IDX]=B[Y_IDX];
  4697. }
  4698. /* VectorXY_crossProduct */
  4699. inline extern double VectorXY_crossProduct(VectorXY A, VectorXY B, VectorXY P){
  4700. double r = (A[Y_IDX]-B[Y_IDX])*(P[X_IDX]-B[X_IDX]) + (B[X_IDX]-A[X_IDX])*(P[Y_IDX]-B[Y_IDX]);
  4701. if(fabs(r) < __FLT_EPSILON__ ) {
  4702. return 0.0;
  4703. }
  4704. return r;
  4705. }
  4706. /* VectorXY_Dot_Product */
  4707. inline extern double VectorXY_Dot_Product(VectorXY A, VectorXY B,VectorXY C){
  4708. double r=(A[X_IDX]-B[X_IDX])*(C[X_IDX]-B[X_IDX])+(A[Y_IDX]-B[Y_IDX])*(C[Y_IDX]-B[Y_IDX]);
  4709. if(fabs(r) < __FLT_EPSILON__ ) {
  4710. return 0.0;
  4711. }
  4712. return r;
  4713. }
  4714. /* VectorXY_BendDirection */
  4715. inline extern int VectorXY_BendDirection(VectorXY A, VectorXY B, VectorXY C){
  4716. /*
  4717. ** Consider traveling from VectorXY A to B to C. If you have to make
  4718. ** a left-turn at B, then this routine returns -1. If C is on the
  4719. ** same line as A and B then return 0. If you make a right turn
  4720. ** at B in order to reach C then return +1.
  4721. */
  4722.  
  4723. /* Algorithm: Rotate AB 90 degrees counter-clockwise. Take
  4724. ** the dot product with BP. The dot produce will be the product
  4725. ** of two (non-negative) magnitudes and the cosine of the angle. So if
  4726. ** the dot product is positive, the bend is to the left, or to the right if
  4727. ** the dot product is negative.
  4728. */
  4729. double r = (A[Y_IDX]-B[Y_IDX])*(C[X_IDX]-B[X_IDX]) + (B[X_IDX]-A[X_IDX])*(C[Y_IDX]-B[Y_IDX]);
  4730. if(fabs(r) < __FLT_EPSILON__ ) return 0;
  4731. if(r>0.0) return -1;
  4732. return 1;
  4733. }
  4734. /* VectorXY_strictlyRightOf */
  4735. inline extern int VectorXY_strictlyRightOf(VectorXY A, VectorXY B, VectorXY P){
  4736. /*
  4737. ** This is a variation on rightOf(). Return 0 only if BP is a continuation
  4738. ** of the line AB. If BP doubles back on AB then return -1.
  4739. */
  4740. int c = VectorXY_BendDirection(A,B,P);
  4741. if( c==0 ){
  4742. double r = (A[X_IDX]-B[X_IDX])*(P[X_IDX]-B[X_IDX]) + (A[Y_IDX]-B[Y_IDX])*(P[Y_IDX]-B[Y_IDX]);
  4743. c = r<0.0 ? +1 : -1;
  4744. }
  4745. return c;
  4746. }
  4747. /* VectorXY_intersect */
  4748. inline extern int VectorXY_intersect(VectorXY A, VectorXY B, VectorXY C, VectorXY D){
  4749. /*
  4750. ** Return TRUE if segments AB and CD intersect
  4751. */
  4752. return VectorXY_BendDirection(A,B,C)*VectorXY_BendDirection(A,B,D)<0 && VectorXY_BendDirection(C,D,A)*VectorXY_BendDirection(C,D,B)<0;
  4753. }
  4754. /* VectorXY_angleOf */
  4755. inline extern double VectorXY_angleOf(VectorXY A, VectorXY B, VectorXY C){
  4756. /*
  4757. ** Compute angle ABC measured counter-clockwise from AB. Return the
  4758. ** result.
  4759. **
  4760. ** This does not need to be a true angular measure as long as it is
  4761. ** monotonically increasing.
  4762. */
  4763. double a1, a2, a3;
  4764. if( VectorXY_SamePoint(A,C) ){
  4765. return M_PI;
  4766. }
  4767. a1 = atan2(B[Y_IDX] - A[Y_IDX], B[X_IDX] - A[X_IDX]);
  4768. a2 = atan2(C[Y_IDX] - B[Y_IDX], C[X_IDX] - B[X_IDX]);
  4769. a3 = a2-a1;
  4770. if( a3>M_PI ) a3 -= 2.0*M_PI;
  4771. if( a3<=-M_PI ) a3 += 2.0*M_PI;
  4772. return a3;
  4773. }
  4774. /* VectorXY_Angle_Three_Point */
  4775. inline extern double VectorXY_Angle_Three_Point(VectorXY A, VectorXY B, VectorXY C){
  4776. /*
  4777. ** Compute angle ABC measured counter-clockwise from AB. Return the
  4778. ** result.
  4779. **
  4780. ** This does not need to be a true angular measure as long as it is
  4781. ** monotonically increasing.
  4782. */
  4783. double a1, a2, a3;
  4784. if( VectorXY_SamePoint(A,C) ){
  4785. return M_PI;
  4786. }
  4787. a1 = atan2(B[Y_IDX] - A[Y_IDX], B[X_IDX] - A[X_IDX]);
  4788. a2 = atan2(C[Y_IDX] - B[Y_IDX], C[X_IDX] - B[X_IDX]);
  4789. a3 = a2-a1;
  4790. if( a3>M_PI ) a3 -= 2.0*M_PI;
  4791. if( a3<=-M_PI ) a3 += 2.0*M_PI;
  4792. return a3;
  4793. }
  4794. /* VectorXY_distance_squared */
  4795. inline extern double VectorXY_distance_squared(VectorXY A, VectorXY B){
  4796. /*
  4797. ** Return the squared distance between two VectorXYs.
  4798. */
  4799. double dx = B[X_IDX] - A[X_IDX];
  4800. double dy = B[Y_IDX] - A[Y_IDX];
  4801. return dx*dx + dy*dy;
  4802. }
  4803. /* VectorXY_distance */
  4804. inline extern double VectorXY_distance(VectorXY A, VectorXY B){
  4805. /*
  4806. ** Return the distance between two VectorXYs.
  4807. */
  4808. double dx = B[X_IDX] - A[X_IDX];
  4809. double dy = B[Y_IDX] - A[Y_IDX];
  4810. return sqrt(dx*dx + dy*dy);
  4811. }
  4812. /* odiemath_cartesian_to_spherical */
  4813. void odiemath_cartesian_to_spherical(VECTOR A,VECTOR R){
  4814. double S;
  4815. /* Work with a copy in case we are writing back to the same pointer */
  4816. double radius,theta,phi;
  4817. radius=VectorXYZ_Magnitude(A);
  4818. S=sqrt(A[X_IDX]*A[X_IDX]+A[Y_IDX]*A[Y_IDX]);
  4819. if (A[X_IDX] > 0.0) {
  4820. theta =asin(A[Y_IDX]/S);
  4821. } else {
  4822. theta =M_PI - asin(A[Y_IDX]/S);
  4823. }
  4824. phi =asin(A[Z_IDX]/R[RADIUS]);
  4825.  
  4826. R[RADIUS]=radius;
  4827. R[THETA]=theta;
  4828. R[PHI]=phi;
  4829. }
  4830. /* odiemath_spherical_to_cartesian */
  4831. void odiemath_spherical_to_cartesian(VECTOR A,VECTOR R){
  4832. /*
  4833. ** Make a copy of the input matrix in case we are outputing back
  4834. ** to the same pointer
  4835. */
  4836. double radius,theta,phi;
  4837. radius=A[RADIUS];
  4838. theta=A[THETA];
  4839. phi=A[PHI];
  4840. R[X_IDX]=radius*cos(theta)*cos(phi);
  4841. R[Y_IDX]=radius*sin(theta)*cos(phi);
  4842. R[Z_IDX]=radius*sin(phi);
  4843. }
  4844. /* odiemath_cylindrical_to_cartesian */
  4845. void odiemath_cylindrical_to_cartesian(VECTOR A,VECTOR R){
  4846. /*
  4847. ** Make a copy of the input matrix in case we are outputing back
  4848. ** to the same pointer
  4849. */
  4850. double radius,theta,z;
  4851. radius=A[RADIUS];
  4852. theta=A[THETA];
  4853. z=A[Z_IDX];
  4854. R[X_IDX]=radius*cos(theta);
  4855. R[Y_IDX]=radius*sin(theta);
  4856. R[Z_IDX]=z;
  4857. }
  4858. /* odiemath_cartesian_to_cylindrical */
  4859. void odiemath_cartesian_to_cylindrical(VECTOR A,VECTOR R){
  4860. /*
  4861. ** Make a copy of the input matrix in case we are outputing back
  4862. ** to the same pointer
  4863. */
  4864. double x,y,z;
  4865. x=A[X_IDX];
  4866. y=A[Y_IDX];
  4867. z=A[Z_IDX];
  4868. R[RADIUS]=sqrt(x*x + y*y);
  4869. R[THETA] =atan2(y,x);
  4870. R[Z_IDX] =z;
  4871. }
  4872. /* *Matrix_To_cartesian */
  4873. const char *Matrix_To_cartesian(MATOBJ *matrix,int form){
  4874. if(matrix->form==form) {
  4875. return NULL;
  4876. }
  4877. switch(matrix->form) {
  4878. case MATFORM_vector_xy:
  4879. case MATFORM_vector_xyz:
  4880. case MATFORM_vector_xyzw:
  4881. break;
  4882. case MATFORM_spherical:
  4883. {
  4884. odiemath_spherical_to_cartesian(matrix->matrix,matrix->matrix);
  4885. matrix->form=form;
  4886. break;
  4887. }
  4888. case MATFORM_polar:
  4889. case MATFORM_cylindrical: {
  4890. odiemath_cylindrical_to_cartesian(matrix->matrix,matrix->matrix);
  4891. matrix->form=form;
  4892. break;
  4893. }
  4894. default: {
  4895. if(matrix->rows==1) {
  4896. int temp=matrix->cols;
  4897. matrix->cols=matrix->rows;
  4898. matrix->rows=temp;
  4899. }
  4900. if(matrix->cols != 1) {
  4901. return "Cannot convert to cartesian";
  4902. }
  4903. }
  4904. }
  4905. switch(form) {
  4906. case MATFORM_vector_xyz:
  4907. matrix->form=form;
  4908. matrix->rows=3;
  4909. matrix->cols=1;
  4910. return NULL;
  4911. case MATFORM_vector_xy:
  4912. matrix->form=form;
  4913. matrix->rows=2;
  4914. matrix->cols=1;
  4915. return NULL;
  4916. }
  4917. return NULL;
  4918. }
  4919. /* *Matrix_To_cylindrical */
  4920. const char *Matrix_To_cylindrical(MATOBJ *matrix,int form){
  4921. if(matrix->form==form) {
  4922. return NULL;
  4923. }
  4924. switch(matrix->form) {
  4925. case MATFORM_polar:
  4926. case MATFORM_cylindrical:
  4927. case MATFORM_vector_xy:
  4928. case MATFORM_vector_xyz:
  4929. case MATFORM_vector_xyzw:
  4930. break;
  4931. default:
  4932. if(Matrix_To_cartesian(matrix,MATFORM_cartesian)) {
  4933. return "Cannot convert to polar";
  4934. }
  4935. }
  4936. if(matrix->form==MATFORM_cartesian) {
  4937. odiemath_cartesian_to_cylindrical(matrix->matrix,matrix->matrix);
  4938. }
  4939. switch(form) {
  4940. case MATFORM_cylindrical:
  4941. matrix->form=form;
  4942. matrix->rows=3;
  4943. matrix->cols=1;
  4944. return NULL;
  4945. case MATFORM_polar:
  4946. matrix->form=form;
  4947. matrix->rows=2;
  4948. matrix->cols=1;
  4949. return NULL;
  4950. }
  4951. return NULL;
  4952. }
  4953. /* *Matrix_To_spherical */
  4954. const char *Matrix_To_spherical(MATOBJ *matrix,int form){
  4955. if(matrix->form==form) {
  4956. return NULL;
  4957. }
  4958. if(Matrix_To_cartesian(matrix,MATFORM_cartesian)) {
  4959. return "Cannot convert to spherical";
  4960. }
  4961. if(matrix->form==MATFORM_cartesian) {
  4962. odiemath_cartesian_to_spherical(matrix->matrix,matrix->matrix);
  4963. }
  4964. matrix->form=form;
  4965. matrix->rows=3;
  4966. matrix->cols=1;
  4967. return NULL;
  4968. }
  4969. /* *VectorXYZ_To_TclObj */
  4970. Tcl_Obj *VectorXYZ_To_TclObj(VectorXYZ R){
  4971. MATOBJ *RESULT;
  4972. RESULT=Odie_MatrixObj_Create(MATFORM_vector_xyz);
  4973. RESULT->matrix[X_IDX]=R[X_IDX];
  4974. RESULT->matrix[Y_IDX]=R[Y_IDX];
  4975. RESULT->matrix[Z_IDX]=R[Z_IDX];
  4976. return Matrix_To_TclObj(RESULT);
  4977. }
  4978. /* Odie_GetVectorXYZFromTclObj */
  4979. int Odie_GetVectorXYZFromTclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,VectorXYZ R){
  4980. Tcl_Obj **elemPtrs;
  4981. int cols,i;
  4982. if(objPtr->typePtr) {
  4983. if(objPtr->typePtr->setFromAnyProc==&MatrixObj_setFromAnyProc) {
  4984. /*
  4985. ** Object is a matrix
  4986. */
  4987. const char *err;
  4988. MATOBJ *value=objPtr->internalRep.otherValuePtr;
  4989. err=Matrix_To_cartesian(value,MATFORM_vector_xyz);
  4990. if(err) {
  4991. Tcl_AppendResult(interp,err,NULL);
  4992. return TCL_ERROR;
  4993. }
  4994. R[X_IDX]=value->matrix[X_IDX];
  4995. R[Y_IDX]=value->matrix[Y_IDX];
  4996. R[Z_IDX]=value->matrix[Z_IDX];
  4997. return TCL_OK;
  4998. }
  4999. }
  5000. /* Step one, Measure the matrix */
  5001. if(Tcl_ListObjGetElements(interp, objPtr, &cols, &elemPtrs)) return TCL_ERROR;
  5002. for(i=0;i<3;i++) {
  5003. double temp;
  5004. if(cols<=i) {
  5005. R[i]=0.0;
  5006. } else {
  5007. if(Tcl_GetDoubleFromObj(interp, elemPtrs[i], &temp)) return TCL_ERROR;
  5008. R[i]=temp;
  5009. }
  5010. }
  5011. return TCL_OK;
  5012. }
  5013. /* VectorXYZ_Scale */
  5014. static inline void VectorXYZ_Scale(VECTOR A,SCALER S){
  5015. A[X_IDX]*=S;
  5016. A[Y_IDX]*=S;
  5017. A[Z_IDX]*=S;
  5018. }
  5019. /* VectorXYZ_Zero */
  5020. static inline void VectorXYZ_Zero(VECTORXYZ A){
  5021. A[X_IDX]=0.0;
  5022. A[Y_IDX]=0.0;
  5023. A[Z_IDX]=0.0;
  5024. }
  5025. /* VectorXYZ_GridAlign */
  5026. static inline void VectorXYZ_GridAlign(VECTORXYZ A,double grid){
  5027. double x,q,grain;
  5028. grain=grid*0.5;
  5029. if(grid<=0) return;
  5030. A[X_IDX]=Vector_GridScaler(A[X_IDX],grid,grain);
  5031. A[Y_IDX]=Vector_GridScaler(A[Y_IDX],grid,grain);
  5032. A[Z_IDX]=Vector_GridScaler(A[Z_IDX],grid,grain);
  5033. }
  5034. /* VectorXYZ_Copy */
  5035. static inline void VectorXYZ_Copy(VECTORXYZ B,VECTORXYZ A){
  5036. B[X_IDX]=A[X_IDX];
  5037. B[Y_IDX]=A[Y_IDX];
  5038. B[Z_IDX]=A[Z_IDX];
  5039. }
  5040. /* VectorXYZ_SamePoint */
  5041. static inline int VectorXYZ_SamePoint(VECTORXYZ A,VECTORXYZ B){
  5042. if(A==B) {
  5043. return 1;
  5044. }
  5045. if(fabs(B[X_IDX]-A[X_IDX])>Vector_Tolerance) return 0;
  5046. if(fabs(B[Y_IDX]-A[Y_IDX])>Vector_Tolerance) return 0;
  5047. if(fabs(B[Z_IDX]-A[Z_IDX])>Vector_Tolerance) return 0;
  5048. return 1;
  5049. }
  5050. /* VectorXYZ_IsZero */
  5051. static inline int VectorXYZ_IsZero(VECTORXYZ A){
  5052. if(!A) return 1;
  5053. if(fabs(A[X_IDX])>Vector_Tolerance) return 0;
  5054. if(fabs(A[Y_IDX])>Vector_Tolerance) return 0;
  5055. if(fabs(A[Z_IDX])>Vector_Tolerance) return 0;
  5056. return 1;
  5057. }
  5058. /* VectorXYZ_Cross_Product */
  5059. static inline void VectorXYZ_Cross_Product(VectorXYZ C,VectorXYZ A,VectorXYZ B){
  5060. C[X_IDX] = A[Y_IDX] * B[Z_IDX] - A[Z_IDX] * B[Y_IDX];
  5061. C[Y_IDX] = A[Z_IDX] * B[X_IDX] - A[X_IDX] * B[Z_IDX];
  5062. C[Z_IDX] = A[X_IDX] * B[Y_IDX] - A[Y_IDX] * B[X_IDX];
  5063. }
  5064. /* VectorXYZ_Add */
  5065. static inline void VectorXYZ_Add(VECTORXYZ C,VECTORXYZ A,VECTORXYZ B){
  5066. C[X_IDX]=B[X_IDX]+A[X_IDX];
  5067. C[Y_IDX]=B[Y_IDX]+A[Y_IDX];
  5068. C[Z_IDX]=B[Z_IDX]+A[Z_IDX];
  5069. }
  5070. /* VectorXYZ_Subtract */
  5071. static inline void VectorXYZ_Subtract(VECTORXYZ C,VECTORXYZ A,VECTORXYZ B){
  5072. C[X_IDX]=A[X_IDX]-B[X_IDX];
  5073. C[Y_IDX]=A[Y_IDX]-B[Y_IDX];
  5074. C[Z_IDX]=A[Z_IDX]-B[Z_IDX];
  5075. }
  5076. /* VectorXYZ_IsOrthagonal */
  5077. static inline int VectorXYZ_IsOrthagonal(VECTORXYZ A,VECTORXYZ B){
  5078. int result=0;
  5079. if((A[X_IDX]-B[X_IDX])>Vector_Tolerance) result++;
  5080. if((A[Y_IDX]-B[Y_IDX])>Vector_Tolerance) result++;
  5081. if((A[Z_IDX]-B[Z_IDX])>Vector_Tolerance) result++;
  5082. return result>1 ? 0 : 1;
  5083. }
  5084. /* VectorXYZ_Midpoint */
  5085. static inline void VectorXYZ_Midpoint(VECTORXYZ C,VECTORXYZ A,VECTORXYZ B){
  5086. C[X_IDX]=(B[X_IDX]-A[X_IDX])*0.5+A[X_IDX];
  5087. C[Y_IDX]=(B[Y_IDX]-A[Y_IDX])*0.5+A[Y_IDX];
  5088. C[Z_IDX]=(B[Z_IDX]-A[Z_IDX])*0.5+A[Z_IDX];
  5089. }
  5090. /* VectorXYZ_Distance */
  5091. static inline double VectorXYZ_Distance(VECTORXYZ A,VECTORXYZ B){
  5092. double dx,dy,dz;
  5093. dx=B[X_IDX]-A[X_IDX];
  5094. dy=B[Y_IDX]-A[Y_IDX];
  5095. dz=B[Z_IDX]-A[Z_IDX];
  5096. return sqrt(dx*dx+dy*dy+dz*dz);
  5097. }
  5098. /* VectorXYZ_DistanceSq */
  5099. static inline double VectorXYZ_DistanceSq(VECTORXYZ A,VECTORXYZ B){
  5100. double dx,dy,dz;
  5101. dx=A[X_IDX]-B[X_IDX];
  5102. dy=A[Y_IDX]-B[Y_IDX];
  5103. dz=A[Z_IDX]-B[Z_IDX];
  5104. return (dx*dx+dy*dy+dz*dz);
  5105. }
  5106. /* VectorXYZ_Dot_Product */
  5107. static inline double VectorXYZ_Dot_Product(VectorXYZ A,VectorXYZ B){
  5108. double r;
  5109. r=A[X_IDX] * B[X_IDX] + A[Y_IDX] * B[Y_IDX] + A[Z_IDX] * B[Z_IDX];
  5110. if(fabs(r)<__FLT_EPSILON__) {
  5111. return 0.0;
  5112. }
  5113. return r;
  5114. }
  5115. /* VectorXYZ_MatrixMultiply */
  5116. static inline void VectorXYZ_MatrixMultiply(VECTORXYZ R,VECTORXYZ A,AFFINE M){
  5117. double temp[4];
  5118. temp[0]=A[X_IDX]*M[AFFINE_IDX_0_0] + A[Y_IDX]*M[AFFINE_IDX_1_0] + A[Z_IDX]* M[AFFINE_IDX_2_0] + M[AFFINE_IDX_3_0];
  5119. temp[1]=A[X_IDX]*M[AFFINE_IDX_0_1] + A[Y_IDX]*M[AFFINE_IDX_1_1] + A[Z_IDX]* M[AFFINE_IDX_2_1] + M[AFFINE_IDX_3_1];
  5120. temp[2]=A[X_IDX]*M[AFFINE_IDX_0_2] + A[Y_IDX]*M[AFFINE_IDX_1_2] + A[Z_IDX]* M[AFFINE_IDX_2_2] + M[AFFINE_IDX_3_2];
  5121. R[0]=temp[0];
  5122. R[1]=temp[1];
  5123. R[2]=temp[2];
  5124. }
  5125. /* VectorXYZ_MagnitudeSq */
  5126. static inline double VectorXYZ_MagnitudeSq(VECTOR A){
  5127. double length=A[0]*A[0]+A[1]*A[1]+A[2]*A[2];
  5128. if(length<Vector_Tolerance) {
  5129. return 0.0;
  5130. }
  5131. return length;
  5132. }
  5133. /* VectorXYZ_Magnitude */
  5134. static inline double VectorXYZ_Magnitude(VECTOR A){
  5135. double length=sqrt(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]);
  5136. if(length<Vector_Tolerance) {
  5137. return 0.0;
  5138. }
  5139. return length;
  5140. }
  5141. /* VectorXYZ_MagnitudeInvSqr */
  5142. static inline double VectorXYZ_MagnitudeInvSqr(VECTOR A){
  5143. double r=A[0]+A[1]+A[2];
  5144. if(fabs(r)<Vector_Tolerance) {
  5145. return NAN;
  5146. }
  5147. return (1.0/(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]));
  5148. }
  5149. /* VectorXYZ_Normalize */
  5150. static inline int VectorXYZ_Normalize(VectorXYZ A){
  5151. double d;
  5152. double r=VectorXYZ_Magnitude(A);
  5153. if(fabs(r) < __FLT_EPSILON__) {
  5154. A[0]=0.0;
  5155. A[1]=0.0;
  5156. A[3]=0.0;
  5157. return 1;
  5158. } else {
  5159. d=1.0 / r;
  5160. A[0]*=d;
  5161. A[1]*=d;
  5162. A[2]*=d;
  5163. return 0;
  5164. }
  5165. }
  5166. /* VectorXYZ_PointIsOnSegment */
  5167. static inline int VectorXYZ_PointIsOnSegment(VectorXYZ POINT,VectorXYZ A,VectorXYZ B){
  5168. VectorXYZ INTERSECT;
  5169. double t;
  5170. t=VectorXYZ_ClosestPointOnSegment(A,B,POINT,INTERSECT);
  5171. if (t<0.0 && t>1.0) return 0;
  5172. if(VectorXYZ_DistanceSq(POINT,INTERSECT)>Vector_Tolerance_Sq) return 0;
  5173. return 1;
  5174. }
  5175. /* VectorXYZ_AxisOfNormal */
  5176. static inline int VectorXYZ_AxisOfNormal(VectorXYZ NORMAL){
  5177. if(fabs(NORMAL[Z_IDX])>fabs(NORMAL[X_IDX])) {
  5178. if (fabs(NORMAL[Z_IDX])>fabs(NORMAL[Y_IDX])) {
  5179. return Z_IDX;
  5180. } else {
  5181. return Y_IDX;
  5182. }
  5183. }
  5184. if (fabs(NORMAL[X_IDX])>fabs(NORMAL[Y_IDX])) {
  5185. return X_IDX;
  5186. } else {
  5187. return Y_IDX;
  5188. }
  5189. }
  5190. /* VectorXYZ_NormalStrictAxisAligned */
  5191. static inline int VectorXYZ_NormalStrictAxisAligned(VectorXYZ NORMAL){
  5192. int i;
  5193. for(i=2;i>=0;i--) {
  5194. if(1.0-fabs(NORMAL[i]) < Vector_Tolerance) return i;
  5195. }
  5196. return -1;
  5197. }
  5198. /* VectorXYZ_AxisAligned */
  5199. static inline int VectorXYZ_AxisAligned(VectorXYZ A,VectorXYZ B,VectorXYZ C){
  5200. int i;
  5201. for(i=2;i>=0;i--) {
  5202. if(fabs((C[i]-B[i])+(B[i]-A[i])) < Vector_Tolerance) return i;
  5203. }
  5204. return -1;
  5205. }
  5206. /* VectorXYZ_BendDirection */
  5207. static inline int VectorXYZ_BendDirection(VectorXYZ A,VectorXYZ B,VectorXYZ C){
  5208. int axis;
  5209. VectorXYZ D1,D2;
  5210. if(VectorXYZ_SamePoint(A,C)) {
  5211. return -1;
  5212. }
  5213. /* If all points are axis aligned. We can treat as a 2d problem */
  5214. axis=VectorXYZ_AxisAligned(A,B,C);
  5215. if(axis==Z_IDX) {
  5216. double r = (A[Y_IDX]-B[Y_IDX])*(C[X_IDX]-B[X_IDX]) + (B[X_IDX]-A[X_IDX])*(C[Y_IDX]-B[Y_IDX]);
  5217. if(fabs(r) < __FLT_EPSILON__) return 0;
  5218. return r<0.0 ? +1 : (r>0.0 ? -1 : 0);
  5219. }
  5220. if(axis==Y_IDX) {
  5221. double r = (A[X_IDX]-B[X_IDX])*(C[Z_IDX]-B[Z_IDX]) + (B[Z_IDX]-A[Z_IDX])*(C[X_IDX]-B[X_IDX]);
  5222. if(fabs(r) < __FLT_EPSILON__) return 0;
  5223. return r<0.0 ? +1 : (r>0.0 ? -1 : 0);
  5224. }
  5225. if(axis==X_IDX) {
  5226. /* All points are axis aligned on Z. We can treat as a 2d problem */
  5227. double r = (A[Z_IDX]-B[Z_IDX])*(C[Y_IDX]-B[Y_IDX]) + (B[Y_IDX]-A[Y_IDX])*(C[Z_IDX]-B[Z_IDX]);
  5228. if(fabs(r) < __FLT_EPSILON__) return 0;
  5229. return r<0.0 ? +1 : (r>0.0 ? -1 : 0);
  5230. }
  5231. VectorXYZ_Cross_Product(D1,B,A);
  5232. VectorXYZ_Cross_Product(D2,C,B);
  5233. if(VectorXYZ_IsZero(D1) && VectorXYZ_IsZero(D2)) {
  5234. /* We must be colinear */
  5235. double r=(A[X_IDX]-B[X_IDX])*(C[X_IDX]-B[X_IDX])+(A[Y_IDX]-B[Y_IDX])*(C[Y_IDX]-B[Y_IDX])+(A[Z_IDX]-B[Z_IDX])*(C[Z_IDX]-B[Z_IDX]);
  5236. if(r<0) {
  5237. return 0;
  5238. }
  5239. return -1;
  5240. }
  5241. /* Gauge the direction of the cross products. If all axis agree, we are pointed the right way */
  5242. if(D1[X_IDX]>=0 && D2[X_IDX]<0) {
  5243. return -1;
  5244. }
  5245. if(D1[Y_IDX]>=0 && D2[Y_IDX]<0) {
  5246. return -1;
  5247. }
  5248. if(D1[Z_IDX]>=0 && D2[Z_IDX]<0) {
  5249. return -1;
  5250. }
  5251. return 1;
  5252. }
  5253. /* VectorXYZ_Angle_Three_Point */
  5254. static inline double VectorXYZ_Angle_Three_Point(VectorXYZ A,VectorXYZ B,VectorXYZ C,VectorXYZ normal){
  5255. double dotprod,num;
  5256. VectorXYZ D1,D2;
  5257. int axis;
  5258. if(VectorXYZ_SamePoint(A,C)) {
  5259. return M_PI;
  5260. }
  5261. axis=VectorXYZ_AxisAligned(A,B,C);
  5262. if(axis==Z_IDX) {
  5263. /* All points are axis aligned on Z. We can treat as a 2d problem */
  5264. return VectorXY_Angle_Three_Point(A,B,C);
  5265. }
  5266. VectorXYZ_Subtract(D1,B,A);
  5267. VectorXYZ_Subtract(D2,C,B);
  5268. num=VectorXYZ_Magnitude(D1)*VectorXYZ_Magnitude(D2);
  5269. if(fabs(num)<Vector_Tolerance) {
  5270. /* At least one of the vectors is zero magnetude
  5271. ** Assume any angle is good */
  5272. return 0.0;
  5273. }
  5274. dotprod=VectorXYZ_Dot_Product(D1,D2);
  5275. return acos(dotprod/num);
  5276. }
  5277. /* VectorXYZ_IsColinear */
  5278. static inline int VectorXYZ_IsColinear(VectorXYZ A,VectorXYZ B,VectorXYZ C){
  5279. double c;
  5280. if(VectorXYZ_SamePoint(A,C)) {
  5281. return 1;
  5282. }
  5283. c=( C[Z_IDX] - A[Z_IDX] ) * ( B[Y_IDX] - A[Y_IDX] ) - ( B[Z_IDX] - A[Z_IDX] ) * ( C[Y_IDX] - A[Y_IDX] );
  5284. if(fabs(c)>Vector_Tolerance) return 0;
  5285. c=( B[Z_IDX] - A[Z_IDX] ) * ( C[X_IDX] - A[X_IDX] ) - ( B[X_IDX] - A[X_IDX] ) * ( C[Z_IDX] - A[Z_IDX] );
  5286. if(fabs(c)>Vector_Tolerance) return 0;
  5287. c=( B[X_IDX] - A[X_IDX] ) * ( C[Y_IDX] - A[Y_IDX] ) - ( B[Y_IDX] - A[Y_IDX] ) * ( C[X_IDX] - A[X_IDX] );
  5288. if(fabs(c)>Vector_Tolerance) return 0;
  5289. return 1;
  5290. }
  5291. /* VectorXYZ_IsCoplaner */
  5292. static inline int VectorXYZ_IsCoplaner(VectorXYZ x1,VectorXYZ x2,VectorXYZ x3,VectorXYZ x4){
  5293. double c;
  5294. VectorXYZ d12,d14,d13,cross;
  5295. VectorXYZ_Subtract(d12,x2,x1);
  5296. VectorXYZ_Subtract(d14,x4,x1);
  5297. VectorXYZ_Cross_Product(cross,d12,d14);
  5298. VectorXYZ_Subtract(d13,x3,x1);
  5299. c=VectorXYZ_Dot_Product(cross,d13);
  5300. if(fabs(c)>Vector_Tolerance) return 0;
  5301. return 1;
  5302. }
  5303. /* VectorXYZ_LineLineCoincident */
  5304. static inline int VectorXYZ_LineLineCoincident(
  5305. VectorXYZ A1, VectorXYZ A2, VectorXYZ B1, VectorXYZ B2,
  5306. VectorXYZ ICEPT1, VectorXYZ ICEPT2
  5307. ){
  5308. int a,b,result=0;
  5309. /*
  5310. ** Optimization - two lines can't be coincident if they don't
  5311. ** occupy the same region of space
  5312. */
  5313. if(!VectorXYZ_BBOX_Overlap_TwoVectors(A1,A2,B1,B2)) {
  5314. return 0;
  5315. }
  5316. if(VectorXYZ_SamePoint(A1,B1)) {
  5317. if(VectorXYZ_SamePoint(A2,B2)) {
  5318. VectorXYZ_Copy(ICEPT1,A1);
  5319. VectorXYZ_Copy(ICEPT2,A2);
  5320. return 30;
  5321. }
  5322. }
  5323. if(VectorXYZ_SamePoint(A2,B1)) {
  5324. if(VectorXYZ_SamePoint(A1,B2)) {
  5325. VectorXYZ_Copy(ICEPT1,A1);
  5326. VectorXYZ_Copy(ICEPT2,A2);
  5327. return 30;
  5328. }
  5329. }
  5330. a=VectorXYZ_IsColinear(A1,B1,B2);
  5331. b=VectorXYZ_IsColinear(A2,B1,B2);
  5332. if(a==0 || b==0) {
  5333. /* The two lines are not colinear */
  5334. int c;
  5335. double x,y;
  5336. c=VectorXYZ_LineLineIntersect(A1,A2,B1,B2,ICEPT1,ICEPT2,&x,&y);
  5337. if(c>0) {
  5338. if(x<=0 || y<=0) return 0;
  5339. if(x>=1 || y>=1) return 0;
  5340. /* True if both intercepts happen on a single point */
  5341. return 1;
  5342. }
  5343. }
  5344. if(VectorXYZ_PointIsOnSegment(A1,B1,B2)) {
  5345. result |= 2;
  5346. }
  5347. if(VectorXYZ_PointIsOnSegment(A2,B1,B2)) {
  5348. result |= 4;
  5349. }
  5350. if(VectorXYZ_PointIsOnSegment(B1,A1,A2)) {
  5351. result |= 8;
  5352. }
  5353. if(VectorXYZ_PointIsOnSegment(B2,A1,A2)) {
  5354. result |= 16;
  5355. }
  5356. /* If the segments touch ends we don't count it as coincident */
  5357. if(result==0 || result==10 || result== 18 || result == 12 || result== 20) {
  5358. return 0;
  5359. }
  5360.  
  5361. if((result & 6)==6) {
  5362. VectorXYZ_Copy(ICEPT1,A1);
  5363. VectorXYZ_Copy(ICEPT2,A2);
  5364. } else if((result & 24)==24) {
  5365. /* Both B on A */
  5366. VectorXYZ_Copy(ICEPT1,B1);
  5367. VectorXYZ_Copy(ICEPT2,B2);
  5368. } else {
  5369. if(result & 2) {
  5370. VectorXYZ_Copy(ICEPT1,A1);
  5371. if(result&8) {
  5372. VectorXYZ_Copy(ICEPT2,B1);
  5373. } else if(result&16) {
  5374. VectorXYZ_Copy(ICEPT2,B2);
  5375. } else {
  5376. VectorXYZ_Copy(ICEPT2,A1);
  5377. }
  5378. } else if(result & 4) {
  5379. VectorXYZ_Copy(ICEPT1,A2);
  5380. if(result&8) {
  5381. VectorXYZ_Copy(ICEPT2,B1);
  5382. } else if(result&16) {
  5383. VectorXYZ_Copy(ICEPT2,B2);
  5384. } else {
  5385. VectorXYZ_Copy(ICEPT2,A2);
  5386. }
  5387. } else if(result & 8) {
  5388. VectorXYZ_Copy(ICEPT1,B1);
  5389. VectorXYZ_Copy(ICEPT1,B2);
  5390. } else {
  5391. VectorXYZ_Copy(ICEPT1,B2);
  5392. VectorXYZ_Copy(ICEPT2,B2);
  5393. }
  5394. }
  5395. return result;
  5396. }
  5397. /* VectorXYZ_LineLineIntersect */
  5398. static inline int VectorXYZ_LineLineIntersect(
  5399. VectorXYZ p1, VectorXYZ p2, VectorXYZ p3, VectorXYZ p4,
  5400. VectorXYZ pA, VectorXYZ pB, double *mua, double *mub
  5401. ){
  5402. VectorXYZ p13,p43,p21;
  5403. double d1343,d4321,d1321,d4343,d2121;
  5404. double numer,denom;
  5405.  
  5406. p13[X_IDX] = p1[X_IDX] - p3[X_IDX];
  5407. p13[Y_IDX] = p1[Y_IDX] - p3[Y_IDX];
  5408. p13[Z_IDX] = p1[Z_IDX] - p3[Z_IDX];
  5409. p43[X_IDX] = p4[X_IDX] - p3[X_IDX];
  5410. p43[Y_IDX] = p4[Y_IDX] - p3[Y_IDX];
  5411. p43[Z_IDX] = p4[Z_IDX] - p3[Z_IDX];
  5412. if (fabs(p43[X_IDX]) < Vector_Tolerance && fabs(p43[Y_IDX]) < Vector_Tolerance && fabs(p43[Z_IDX]) < Vector_Tolerance)
  5413. return(0);
  5414. p21[X_IDX] = p2[X_IDX] - p1[X_IDX];
  5415. p21[Y_IDX] = p2[Y_IDX] - p1[Y_IDX];
  5416. p21[Z_IDX] = p2[Z_IDX] - p1[Z_IDX];
  5417. if (fabs(p21[X_IDX]) < Vector_Tolerance && fabs(p21[Y_IDX]) < Vector_Tolerance && fabs(p21[Z_IDX]) < Vector_Tolerance)
  5418. return(0);
  5419.  
  5420. d1343 = p13[X_IDX] * p43[X_IDX] + p13[Y_IDX] * p43[Y_IDX] + p13[Z_IDX] * p43[Z_IDX];
  5421. d4321 = p43[X_IDX] * p21[X_IDX] + p43[Y_IDX] * p21[Y_IDX] + p43[Z_IDX] * p21[Z_IDX];
  5422. d1321 = p13[X_IDX] * p21[X_IDX] + p13[Y_IDX] * p21[Y_IDX] + p13[Z_IDX] * p21[Z_IDX];
  5423. d4343 = p43[X_IDX] * p43[X_IDX] + p43[Y_IDX] * p43[Y_IDX] + p43[Z_IDX] * p43[Z_IDX];
  5424. d2121 = p21[X_IDX] * p21[X_IDX] + p21[Y_IDX] * p21[Y_IDX] + p21[Z_IDX] * p21[Z_IDX];
  5425.  
  5426. denom = d2121 * d4343 - d4321 * d4321;
  5427. if (fabs(denom) < __FLT_EPSILON__)
  5428. return(0);
  5429. numer = d1343 * d4321 - d1321 * d4343;
  5430.  
  5431. *mua = numer / denom;
  5432. *mub = (d1343 + d4321 * (*mua)) / d4343;
  5433.  
  5434. pA[X_IDX] = p1[X_IDX] + *mua * p21[X_IDX];
  5435. pA[Y_IDX] = p1[Y_IDX] + *mua * p21[Y_IDX];
  5436. pA[Z_IDX] = p1[Z_IDX] + *mua * p21[Z_IDX];
  5437. pB[X_IDX] = p3[X_IDX] + *mub * p43[X_IDX];
  5438. pB[Y_IDX] = p3[Y_IDX] + *mub * p43[Y_IDX];
  5439. pB[Z_IDX] = p3[Z_IDX] + *mub * p43[Z_IDX];
  5440. return(1);
  5441. }
  5442. /* VectorXYZ_ClosestPointOnSegment */
  5443. static double VectorXYZ_ClosestPointOnSegment (
  5444. VectorXYZ A, VectorXYZ B, /* End points of the line segment */
  5445. VectorXYZ X, /* The point outside the line */
  5446. VectorXYZ R /* Write closest point on line segment here */
  5447. ){
  5448. VectorXYZ v1, v2;
  5449. double t, s,mag;
  5450.  
  5451. VectorXYZ_Subtract(v1, X, A);
  5452. VectorXYZ_Subtract(v2, B, A);
  5453. mag=VectorXYZ_MagnitudeSq(v2);
  5454. if(mag<Vector_Tolerance_Sq) {
  5455. /* A, B and X are on the same point */
  5456. R[X_IDX] = A[X_IDX];
  5457. R[Y_IDX] = A[Y_IDX];
  5458. R[Z_IDX] = A[Z_IDX];
  5459. return 0.5;
  5460. }
  5461. t = VectorXYZ_Dot_Product(v1, v2)/VectorXYZ_MagnitudeSq(v2);
  5462. if( t<0.0 ){
  5463. VectorXYZ_Copy(R,A);
  5464. } else if( t>1.0 ){
  5465. VectorXYZ_Copy(R,B);
  5466. } else {
  5467. s = 1.0 - t;
  5468. R[X_IDX] = A[X_IDX]*s + B[X_IDX]*t;
  5469. R[Y_IDX] = A[Y_IDX]*s + B[Y_IDX]*t;
  5470. R[Z_IDX] = A[Z_IDX]*s + B[Z_IDX]*t;
  5471. }
  5472. return t;
  5473. }
  5474. /* VectorXYX_solve3by3 */
  5475. static int VectorXYX_solve3by3(double *m){
  5476. int i, j, k;
  5477. double x, y, scale;
  5478. /* Process three rows from top to bottom */
  5479. for(i=0; i<3; i++){
  5480. /* Find the pivot for the i-th row */
  5481. x = fabs(m[i*5]);
  5482. k = i;
  5483. for(j=i+1; j<3; j++){
  5484. y = fabs(m[j*4+i]);
  5485. if( y>x ){
  5486. x = y;
  5487. k = j;
  5488. }
  5489. }
  5490.  
  5491. /* Swap in the pivot */
  5492. if( k>i ){
  5493. double t;
  5494. int n, p, q;
  5495. p = i*5;
  5496. q = k*4+i;
  5497. for(n=i; n<4; n++, p++, q++){
  5498. t = m[p];
  5499. m[p] = m[q];
  5500. m[q] = t;
  5501. }
  5502. }
  5503.  
  5504. /* No solution if the pivot is 0.0 */
  5505. if( m[i*5]==0.0 ) {
  5506. return 1;
  5507. }
  5508.  
  5509. /* Divide the i-th row by the pivot */
  5510. scale = m[i*5];
  5511. for(j=i; j<4; j++){
  5512. m[i*4+j] /= scale;
  5513. }
  5514.  
  5515. /* Add the i-th row to other rows to eliminate the i-th term. */
  5516. for(j=i+1; j<3; j++){
  5517. double scale = -m[j*4+i];
  5518. for(k=i; k<4; k++){
  5519. m[j*4+k] += m[i*4+k]*scale;
  5520. }
  5521. }
  5522. }
  5523.  
  5524. /* Now we have an upper triangular matrix with a diagonal of 1.
  5525. ** Finishing the solution is easy */
  5526. for(i=1; i>=0; i--){
  5527. for(j=2; j>i; j--){
  5528. m[i*4+3] -= m[j*4+3]*m[i*4+j];
  5529. }
  5530. }
  5531. return 0;
  5532. }
  5533. /* VectorXYZ_TriangleLineIntersect */
  5534. static double VectorXYZ_TriangleLineIntersect(
  5535. VectorXYZ A, VectorXYZ B, VectorXYZ C, /* The triangle we are trying to intersect */
  5536. VectorXYZ pStart, /* Start of the line segment */
  5537. VectorXYZ pEnd, /* End of the line segment */
  5538. VectorXYZ pIntersect /* Point of intersection written here if not NULL */
  5539. ){
  5540. double s, t;
  5541. double m[12];
  5542. m[0] = pStart[X_IDX] - pEnd[X_IDX];
  5543. m[1] = B[X_IDX] - A[X_IDX];
  5544. m[2] = C[X_IDX] - A[X_IDX];
  5545. m[3] = pStart[X_IDX] - A[X_IDX];
  5546. m[4] = pStart[Y_IDX] - pEnd[Y_IDX];
  5547. m[5] = B[Y_IDX] - A[Y_IDX];
  5548. m[6] = C[Y_IDX] - A[Y_IDX];
  5549. m[7] = pStart[Y_IDX] - A[Y_IDX];
  5550. m[8] = pStart[Z_IDX] - pEnd[Z_IDX];
  5551. m[9] = B[Z_IDX] - A[Z_IDX];
  5552. m[10] = C[Z_IDX] - A[Z_IDX];
  5553. m[11] = pStart[Z_IDX] - A[Z_IDX];
  5554. if( VectorXYX_solve3by3(m) ){
  5555. /* The line is parallel or coplanar with the triangle */
  5556. return -1.0;
  5557. }
  5558. t = m[3];
  5559. if( t<0.0 || t>1.0 ){
  5560. /* The point of intersection is off the ends of the line segment */
  5561. return -1.0;
  5562. }
  5563. if( m[7]<0.0 || m[7]>1.0 || m[11]<0.0 || m[11]>1.0 || (m[7]+m[11])>1.0 ){
  5564. /* The point of intersection is outside of the triangle boundary */
  5565. return -1.0;
  5566. }
  5567. s = 1.0 - t;
  5568. pIntersect[X_IDX] = pStart[X_IDX]*s + pEnd[X_IDX]*t;
  5569. pIntersect[Y_IDX] = pStart[Y_IDX]*s + pEnd[Y_IDX]*t;
  5570. pIntersect[Z_IDX] = pStart[Z_IDX]*s + pEnd[Z_IDX]*t;
  5571. return t;
  5572. }
  5573. /* VectorXYZ_Normal_of_Three_Points */
  5574. static inline void VectorXYZ_Normal_of_Three_Points(VectorXYZ normal,VectorXYZ A,VectorXYZ B,VectorXYZ C){
  5575. VectorXYZ one,two;
  5576. VectorXYZ_Subtract(one, B, A);
  5577. VectorXYZ_Subtract(two, C, A);
  5578. normal[X_IDX] = one[Y_IDX]*two[Z_IDX] - one[Z_IDX]*two[Y_IDX];
  5579. normal[Y_IDX] = one[Z_IDX]*two[X_IDX] - one[X_IDX]*two[Z_IDX];
  5580. normal[Z_IDX] = one[X_IDX]*two[Y_IDX] - one[Y_IDX]*two[X_IDX];
  5581. }
  5582. /* VectorXYZ_LineSphereIntersect */
  5583. int VectorXYZ_LineSphereIntersect(
  5584. double p1_x, double p1_y, double p1_z,
  5585. double p2_x, double p2_y, double p2_z,
  5586. double sc_x, double sc_y, double sc_z,
  5587. double r,
  5588. double *mu1, double *mu2){
  5589. /*
  5590. ** Detect the intersection of a line and a sphere
  5591. ** Adapted from: http://http://paulbourke.net/geometry/circlesphere/raysphere.c
  5592. */
  5593. double a,b,c;
  5594. double bb4ac;
  5595. double dp_x,dp_y,dp_z;
  5596. *mu1 = 0;
  5597. *mu2 = 0;
  5598. dp_x = p2_x - p1_x;
  5599. dp_y = p2_y - p1_y;
  5600. dp_z = p2_z - p1_z;
  5601. a = dp_x * dp_x + dp_y * dp_y + dp_z * dp_z;
  5602. b = 2 * (dp_x * (p1_x - sc_x) + dp_y * (p1_y - sc_y) + dp_z * (p1_z - sc_z));
  5603. c = sc_x * sc_x + sc_y * sc_y + sc_z * sc_z;
  5604. c += p1_x * p1_x + p1_y * p1_y + p1_z * p1_z;
  5605. c -= 2 * (sc_x * p1_x + sc_y * p1_y + sc_z * p1_z);
  5606. c -= r * r;
  5607. bb4ac = b * b - 4 * a * c;
  5608. if (ODIE_Real_Is_Zero(a) || bb4ac < 0) {
  5609. return(0);
  5610. }
  5611.  
  5612. *mu1 = (-b + sqrt(bb4ac)) / (2 * a);
  5613. *mu2 = (-b - sqrt(bb4ac)) / (2 * a);
  5614. return(1);
  5615. }
  5616. /* *VectorXYZ_ToString */
  5617. char *VectorXYZ_ToString(VectorXYZ VECTOR){
  5618. char *out=Tcl_Alloc(128);
  5619. sprintf(out,"<%g %g %g>",(float)VECTOR[X_IDX],(float)VECTOR[Y_IDX],(float)VECTOR[Z_IDX]);
  5620. return out;
  5621. }
  5622. /* Vector_Set_Tolerance */
  5623. void Vector_Set_Tolerance(double newvalue){
  5624. Vector_Tolerance=newvalue;
  5625. Vector_Tolerance_Sq=newvalue*newvalue;
  5626. }
  5627. /* *Vector_Alloc */
  5628. double *Vector_Alloc(size_t size){
  5629. double *ptr;
  5630. if(size<128) {
  5631. size=128;
  5632. }
  5633. ptr=(double*)ckalloc(size);
  5634. memset(ptr,0,size);
  5635. return ptr;
  5636. }
  5637. /* Odie_Matrix_AABBXYZ_From_TclObj */
  5638. STUB_EXPORT int Odie_Matrix_AABBXYZ_From_TclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,AABBXYZ ptr){
  5639. Odie_MatrixObj *T;
  5640. if(Odie_GetMatrixFromTclObj(interp,objPtr,MATFORM_aabb_xyz,&T)) return TCL_ERROR;
  5641. memcpy(ptr,T->matrix,sizeof(AABBXYZ));
  5642. return TCL_OK;
  5643. }
  5644. /* *Odie_Matrix_AABBXYZ_To_TclObj */
  5645. STUB_EXPORT Tcl_Obj *Odie_Matrix_AABBXYZ_To_TclObj(AABBXYZ ptr){
  5646. Odie_MatrixObj *C;
  5647. Tcl_Obj *result;
  5648. C=Odie_MatrixObj_Create(MATFORM_aabb_xyz);
  5649. memcpy(C->matrix,ptr,sizeof(AABBXYZ));
  5650. result=Matrix_To_TclObj(C);
  5651. return result;
  5652. }
  5653. /* Odie_Matrix_AFFINE_From_TclObj */
  5654. STUB_EXPORT int Odie_Matrix_AFFINE_From_TclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,AFFINE ptr){
  5655. Odie_MatrixObj *T;
  5656. if(Odie_GetMatrixFromTclObj(interp,objPtr,MATFORM_affine,&T)) return TCL_ERROR;
  5657. memcpy(ptr,T->matrix,sizeof(AFFINE));
  5658. return TCL_OK;
  5659. }
  5660. /* *Odie_Matrix_AFFINE_To_TclObj */
  5661. STUB_EXPORT Tcl_Obj *Odie_Matrix_AFFINE_To_TclObj(AFFINE ptr){
  5662. Odie_MatrixObj *C;
  5663. Tcl_Obj *result;
  5664. C=Odie_MatrixObj_Create(MATFORM_affine);
  5665. memcpy(C->matrix,ptr,sizeof(AFFINE));
  5666. result=Matrix_To_TclObj(C);
  5667. return result;
  5668. }
  5669. /* Odie_Matrix_BBOXXY_From_TclObj */
  5670. STUB_EXPORT int Odie_Matrix_BBOXXY_From_TclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,BBOXXY ptr){
  5671. Odie_MatrixObj *T;
  5672. if(Odie_GetMatrixFromTclObj(interp,objPtr,MATFORM_bbox_xy,&T)) return TCL_ERROR;
  5673. memcpy(ptr,T->matrix,sizeof(BBOXXY));
  5674. return TCL_OK;
  5675. }
  5676. /* *Odie_Matrix_BBOXXY_To_TclObj */
  5677. STUB_EXPORT Tcl_Obj *Odie_Matrix_BBOXXY_To_TclObj(BBOXXY ptr){
  5678. Odie_MatrixObj *C;
  5679. Tcl_Obj *result;
  5680. C=Odie_MatrixObj_Create(MATFORM_bbox_xy);
  5681. memcpy(C->matrix,ptr,sizeof(BBOXXY));
  5682. result=Matrix_To_TclObj(C);
  5683. return result;
  5684. }
  5685. /* Odie_Matrix_AFFINE3X3_From_TclObj */
  5686. STUB_EXPORT int Odie_Matrix_AFFINE3X3_From_TclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,AFFINE3X3 ptr){
  5687. Odie_MatrixObj *T;
  5688. if(Odie_GetMatrixFromTclObj(interp,objPtr,MATFORM_mat3,&T)) return TCL_ERROR;
  5689. memcpy(ptr,T->matrix,sizeof(AFFINE3X3));
  5690. return TCL_OK;
  5691. }
  5692. /* *Odie_Matrix_AFFINE3X3_To_TclObj */
  5693. STUB_EXPORT Tcl_Obj *Odie_Matrix_AFFINE3X3_To_TclObj(AFFINE3X3 ptr){
  5694. Odie_MatrixObj *C;
  5695. Tcl_Obj *result;
  5696. C=Odie_MatrixObj_Create(MATFORM_mat3);
  5697. memcpy(C->matrix,ptr,sizeof(AFFINE3X3));
  5698. result=Matrix_To_TclObj(C);
  5699. return result;
  5700. }
  5701. /* Odie_Matrix_QUATERNION_From_TclObj */
  5702. STUB_EXPORT int Odie_Matrix_QUATERNION_From_TclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,QUATERNION ptr){
  5703. Odie_MatrixObj *T;
  5704. if(Odie_GetMatrixFromTclObj(interp,objPtr,MATFORM_quaternion,&T)) return TCL_ERROR;
  5705. memcpy(ptr,T->matrix,sizeof(QUATERNION));
  5706. return TCL_OK;
  5707. }
  5708. /* *Odie_Matrix_QUATERNION_To_TclObj */
  5709. STUB_EXPORT Tcl_Obj *Odie_Matrix_QUATERNION_To_TclObj(QUATERNION ptr){
  5710. Odie_MatrixObj *C;
  5711. Tcl_Obj *result;
  5712. C=Odie_MatrixObj_Create(MATFORM_quaternion);
  5713. memcpy(C->matrix,ptr,sizeof(QUATERNION));
  5714. result=Matrix_To_TclObj(C);
  5715. return result;
  5716. }
  5717. /* Odie_Matrix_VECTORXY_From_TclObj */
  5718. STUB_EXPORT int Odie_Matrix_VECTORXY_From_TclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,VECTORXY ptr){
  5719. Odie_MatrixObj *T;
  5720. if(Odie_GetMatrixFromTclObj(interp,objPtr,MATFORM_vector_xy,&T)) return TCL_ERROR;
  5721. memcpy(ptr,T->matrix,sizeof(VECTORXY));
  5722. return TCL_OK;
  5723. }
  5724. /* *Odie_Matrix_VECTORXY_To_TclObj */
  5725. STUB_EXPORT Tcl_Obj *Odie_Matrix_VECTORXY_To_TclObj(VECTORXY ptr){
  5726. Odie_MatrixObj *C;
  5727. Tcl_Obj *result;
  5728. C=Odie_MatrixObj_Create(MATFORM_vector_xy);
  5729. memcpy(C->matrix,ptr,sizeof(VECTORXY));
  5730. result=Matrix_To_TclObj(C);
  5731. return result;
  5732. }
  5733. /* Odie_Matrix_VectorXYZ_From_TclObj */
  5734. STUB_EXPORT int Odie_Matrix_VectorXYZ_From_TclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,VectorXYZ ptr){
  5735. Odie_MatrixObj *T;
  5736. if(Odie_GetMatrixFromTclObj(interp,objPtr,MATFORM_vector_xyz,&T)) return TCL_ERROR;
  5737. memcpy(ptr,T->matrix,sizeof(VectorXYZ));
  5738. return TCL_OK;
  5739. }
  5740. /* *Odie_Matrix_VectorXYZ_To_TclObj */
  5741. STUB_EXPORT Tcl_Obj *Odie_Matrix_VectorXYZ_To_TclObj(VectorXYZ ptr){
  5742. Odie_MatrixObj *C;
  5743. Tcl_Obj *result;
  5744. C=Odie_MatrixObj_Create(MATFORM_vector_xyz);
  5745. memcpy(C->matrix,ptr,sizeof(VectorXYZ));
  5746. result=Matrix_To_TclObj(C);
  5747. return result;
  5748. }
  5749. /* Odie_GetIntFromObj */
  5750. int Odie_GetIntFromObj(Tcl_Interp *interp,Tcl_Obj *tclObj,int *result){
  5751. if(!Tcl_GetIntFromObj(NULL,tclObj,result)) {
  5752. return TCL_OK;
  5753. }
  5754. double s;
  5755. if(Tcl_GetDoubleFromObj(interp,tclObj,&s)) return TCL_ERROR;
  5756. *result=(int)round(s);
  5757. return TCL_OK;
  5758. }
  5759. /* Odie_GetMatrixFromTclObj */
  5760. int Odie_GetMatrixFromTclObj(Tcl_Interp *interp,Tcl_Obj *tclObj,int form,Odie_MatrixObj **result){
  5761. const char *(*xConvertToForm)(MATOBJ*,int)=MatrixForms[form].xConvertToForm;
  5762. const char *error;
  5763. *result=NULL;
  5764. if(MatrixObj_setFromAnyProc(interp,tclObj)) {
  5765. return TCL_ERROR;
  5766. }
  5767. *result=tclObj->internalRep.otherValuePtr;
  5768. if(!xConvertToForm) {
  5769. return TCL_OK;
  5770. }
  5771. error=xConvertToForm(*result,form);
  5772. if(error) {
  5773. Tcl_SetObjResult(interp,Tcl_NewStringObj(error,-1));
  5774. return TCL_ERROR;
  5775. }
  5776. return TCL_OK;
  5777. }
  5778. /* *Odie_Matrix_Duplicate */
  5779. Odie_MatrixObj *Odie_Matrix_Duplicate(Odie_MatrixObj *src){
  5780. Odie_MatrixObj *dest;
  5781. size_t matsize,size;
  5782. matsize=sizeof(double)*src->rows*src->cols;
  5783. if(matsize<128) {
  5784. matsize=128;
  5785. }
  5786. size=matsize+sizeof(Odie_MatrixObj);
  5787. dest=(Odie_MatrixObj *)Odie_Alloc(size);
  5788. memcpy(dest,src,size);
  5789. return dest;
  5790. }
  5791. /* *Odie_MatrixObj_Create_NXN */
  5792. Odie_MatrixObj *Odie_MatrixObj_Create_NXN(int rows,int cols){
  5793. Odie_MatrixObj *new;
  5794. void *p;
  5795. int size_t;
  5796. size_t=rows*cols*sizeof(double);
  5797. if(size_t<128) {
  5798. size_t=128;
  5799. }
  5800. p=Odie_Alloc(sizeof(Odie_MatrixObj)+size_t);
  5801. new=p;
  5802. new->form=MATFORM_null;
  5803. new->cols=cols;
  5804. new->rows=rows;
  5805. return new;
  5806. }
  5807. /* *Odie_MatrixObj_Create */
  5808. Odie_MatrixObj *Odie_MatrixObj_Create(int form){
  5809. Odie_MatrixObj *new;
  5810. int rows,cols;
  5811. void *p;
  5812. int size_t;
  5813. rows=MatrixForms[form].rows;
  5814. cols=MatrixForms[form].cols;
  5815. size_t=rows*cols*sizeof(double);
  5816. if(size_t<128) {
  5817. size_t=128;
  5818. }
  5819. p=Odie_Alloc(sizeof(Odie_MatrixObj)+size_t);
  5820. new=p;
  5821. new->form=form;
  5822. new->cols=cols;
  5823. new->rows=rows;
  5824. return new;
  5825. }
  5826. /* Matrix_Free */
  5827. void Matrix_Free(Odie_MatrixObj *matrix){
  5828. if(!matrix) return;
  5829. matrix->refCount--;
  5830. /*
  5831. ** Seems counter intuitive, but freeing when refCount==0 causes
  5832. ** Tcl to Crash
  5833. */
  5834. if(matrix->refCount<0) {
  5835. Odie_Free(matrix);
  5836. }
  5837. }
  5838. /* *Matrix_ToAny */
  5839. const char *Matrix_ToAny(Odie_MatrixObj *matrix,int form){
  5840. /* Accept any input */
  5841. matrix->form=form;
  5842. return NULL;
  5843. }
  5844. /* Odie_TclObj_To_MatrixObj */
  5845. int Odie_TclObj_To_MatrixObj(Tcl_Interp *interp,Tcl_Obj *listPtr,Odie_MatrixObj **matrix){
  5846. Odie_MatrixObj *pNew;
  5847. Tcl_Obj **rowPtrs;
  5848. Tcl_Obj **elemPtrs;
  5849. int result;
  5850. int rows,cols;
  5851. int idx,i,j;
  5852. int len;
  5853. /* Step one, Measure the matrix */
  5854. result = Tcl_ListObjGetElements(interp, listPtr, &rows, &rowPtrs);
  5855. if (result != TCL_OK) {
  5856. return result;
  5857. }
  5858. if(rows<1) {
  5859. Tcl_AppendResult(interp, "Could not interpret matrix", 0);
  5860. return TCL_ERROR;
  5861. }
  5862. result = Tcl_ListObjGetElements(interp, rowPtrs[0], &cols, &elemPtrs);
  5863. if (result != TCL_OK) {
  5864. return result;
  5865. }
  5866. /*
  5867. ** For NULL form, we pass the rows and cols
  5868. ** via the data structure
  5869. */
  5870. pNew=Odie_MatrixObj_Create_NXN(rows,cols);
  5871.  
  5872. idx=-1;
  5873. for(i=0;i<rows;i++) {
  5874. result = Tcl_ListObjGetElements(interp, rowPtrs[i], &len, &elemPtrs);
  5875. if (result != TCL_OK) {
  5876. return result;
  5877. }
  5878. if(len != cols) {
  5879. Tcl_SetObjResult(interp,Tcl_NewStringObj("Columns are not uniform",-1));
  5880. Matrix_Free(pNew);
  5881. return TCL_ERROR;
  5882. }
  5883. for(j=0;j<len;j++) {
  5884. double temp;
  5885. idx++;
  5886. result = Tcl_GetDoubleFromObj(interp, elemPtrs[j], &temp);
  5887. if (result != TCL_OK) {
  5888. return result;
  5889. }
  5890. *(pNew->matrix+idx)=(SCALER)temp;
  5891. }
  5892. }
  5893. *matrix=pNew;
  5894. return TCL_OK;
  5895. }
  5896. /* *Matrix_To_TclObj */
  5897. Tcl_Obj *Matrix_To_TclObj(Odie_MatrixObj *matrix){
  5898. Tcl_Obj *dest=Tcl_NewObj();
  5899. dest->typePtr=&matrix_tclobjtype;
  5900. dest->internalRep.otherValuePtr=matrix;
  5901. matrix->refCount++;
  5902. Tcl_InvalidateStringRep(dest);
  5903. return dest;
  5904. }
  5905. /* MatrixObj_setFromAnyProc */
  5906. int MatrixObj_setFromAnyProc(Tcl_Interp *interp,Tcl_Obj *objPtr){
  5907. if(objPtr->typePtr) {
  5908. if(objPtr->typePtr->setFromAnyProc==&MatrixObj_setFromAnyProc) {
  5909. /*
  5910. ** Object is already of the type requested
  5911. */
  5912. return TCL_OK;
  5913. }
  5914. }
  5915. Odie_MatrixObj *matrix;
  5916. if(Odie_TclObj_To_MatrixObj(interp,objPtr,&matrix)) {
  5917. return TCL_ERROR;
  5918. }
  5919. objPtr->internalRep.otherValuePtr=matrix;
  5920. objPtr->typePtr=&matrix_tclobjtype;
  5921. return TCL_OK;
  5922. }
  5923. /* MatrixObj_updateStringProc */
  5924. void MatrixObj_updateStringProc(Tcl_Obj *objPtr){
  5925. float value;
  5926. char outbuffer[128];
  5927. Tcl_DString result;
  5928. Odie_MatrixObj *matrix=objPtr->internalRep.otherValuePtr;
  5929. int rows,cols;
  5930. register int j;
  5931. /* Step 1, dimension matrix */
  5932. rows = matrix->rows;
  5933. cols = matrix->cols;
  5934. Tcl_DStringInit(&result);
  5935. if(cols==1) {
  5936. /*
  5937. * Output single-row matrices (i.e. vectors)
  5938. * as a single tcl list (rather than nest them
  5939. * as a list within a list)
  5940. */
  5941. for(j=0;j<rows;j++) {
  5942. value=(float)*(matrix->matrix+j);
  5943. //Tcl_PrintDouble(NULL,value,outbuffer);
  5944. sprintf(outbuffer,"%g",value);
  5945. Tcl_DStringAppendElement(&result,outbuffer);
  5946. }
  5947. } else if(rows==1) {
  5948. /*
  5949. * Output single-row matrices (i.e. vectors)
  5950. * as a single tcl list (rather than nest them
  5951. * as a list within a list)
  5952. */
  5953. for(j=0;j<cols;j++) {
  5954. value=(float)*(matrix->matrix+j);
  5955. //Tcl_PrintDouble(NULL,value,outbuffer);
  5956. sprintf(outbuffer,"%g",value);
  5957. Tcl_DStringAppendElement(&result,outbuffer);
  5958. }
  5959. } else {
  5960. register int i,idx=0;
  5961. for(i=0;i<rows;i++) {
  5962. Tcl_DStringStartSublist(&result);
  5963. for(j=0;j<cols;j++) {
  5964. idx=(i*cols)+j;
  5965. value=(float)*(matrix->matrix+idx);
  5966. sprintf(outbuffer,"%g",value);
  5967. Tcl_DStringAppendElement(&result,outbuffer);
  5968. }
  5969. Tcl_DStringEndSublist(&result);
  5970. }
  5971. }
  5972. objPtr->length=Tcl_DStringLength(&result);
  5973. objPtr->bytes=Odie_Alloc(objPtr->length+1);
  5974. memcpy(objPtr->bytes,Tcl_DStringValue(&result),objPtr->length);
  5975. objPtr->bytes[objPtr->length]='\0';
  5976. Tcl_DStringFree(&result);
  5977. }
  5978. /* MatrixObj_dupIntRepProc */
  5979. void MatrixObj_dupIntRepProc(Tcl_Obj *srcPtr,Tcl_Obj *dupPtr){
  5980. Odie_MatrixObj *srcmatrix=srcPtr->internalRep.otherValuePtr;
  5981. Odie_MatrixObj *dupmatrix=Odie_Matrix_Duplicate(srcmatrix);
  5982. dupPtr->typePtr=srcPtr->typePtr;
  5983. dupPtr->internalRep.otherValuePtr=dupmatrix;
  5984. Tcl_InvalidateStringRep(dupPtr);
  5985. }
  5986. /* MatrixObj_freeIntRepProc */
  5987. void MatrixObj_freeIntRepProc(Tcl_Obj *objPtr){
  5988. if(!objPtr->internalRep.otherValuePtr) return;
  5989. Odie_MatrixObj *matrix=objPtr->internalRep.otherValuePtr;
  5990. Matrix_Free(matrix);
  5991. objPtr->typePtr=NULL;
  5992. objPtr->internalRep.otherValuePtr=NULL;
  5993. }
  5994. /* MatrixObjType_Init */
  5995. int MatrixObjType_Init(Tcl_Interp *interp){
  5996. Tcl_RegisterObjType(&matrix_tclobjtype);
  5997. return TCL_OK;
  5998. }
  5999. /* ODIE_Real_Is_Zero */
  6000. inline extern int ODIE_Real_Is_Zero(double x){
  6001. if(fabs(x) < __FLT_EPSILON__) {
  6002. return 1;
  6003. }
  6004. return 0;
  6005. }
  6006. /* ODIE_Fuzzy_Compare_TclObj */
  6007. int ODIE_Fuzzy_Compare_TclObj(Tcl_Obj *avalue,Tcl_Obj *bvalue,double epsilon){
  6008. int result;
  6009. char *a,*b;
  6010. double ax,bx;
  6011. int ai,bi;
  6012. int atype,btype,stringcmp=0;
  6013. ClientData internalPtrA,internalPtrB;
  6014.  
  6015. if(Tcl_GetIntFromObj(NULL,avalue,&ai)) goto doublecmp;
  6016. if(Tcl_GetIntFromObj(NULL,bvalue,&bi)) goto doublecmp;
  6017. if(ai==bi) {
  6018. return 0;
  6019. } else {
  6020. result=ai>bi ? 1 : -1;
  6021. }
  6022.  
  6023. doublecmp:
  6024. if(Tcl_GetDoubleFromObj(NULL,avalue,&ax)) goto stringcmp;
  6025. if(Tcl_GetDoubleFromObj(NULL,bvalue,&bx)) goto stringcmp;
  6026. result=ODIE_Fuzzy_Compare(ax,bx,epsilon);
  6027. return result;
  6028.  
  6029. stringcmp:
  6030. a=Tcl_GetString(avalue);
  6031. b=Tcl_GetString(bvalue);
  6032. return strcmp(a,b);
  6033. }
  6034. /* ODIE_FuzzyNumber */
  6035. double ODIE_FuzzyNumber(double ax){
  6036. char newstring[128];
  6037. int expa;
  6038. double siga,ipart,fpart,result;
  6039. if (Odie_IsNaN(ax)) {
  6040. return ax;
  6041. }
  6042. if(Odie_IsInfinite(ax)) {
  6043. return ax;
  6044. }
  6045. if(ODIE_Real_Is_Zero(ax)) {
  6046. return 0;
  6047. }
  6048. siga=frexp(ax,&expa);
  6049. fpart=modf(ldexp(siga,10),&ipart);
  6050. return ldexp(ipart,expa-10);
  6051. }
  6052. /* *ODIE_NewFuzzyObj */
  6053. Tcl_Obj *ODIE_NewFuzzyObj(float ax){
  6054. double bx;
  6055. const char *use_format="%g";
  6056. char newstring[128];
  6057. if (Odie_IsNaN(ax)) {
  6058. return Tcl_NewDoubleObj(ax);
  6059. }
  6060. if(Odie_IsInfinite(ax)) {
  6061. return Tcl_NewDoubleObj(ax);
  6062. }
  6063. if(ODIE_Real_Is_Zero(ax)) {
  6064. return ODIE_REAL_ZERO();
  6065. }
  6066. bx=fabs(ax);
  6067. if(bx>1000000.0) {
  6068. use_format="%g";
  6069. } else if(bx>1000.0) {
  6070. use_format="%.0f";
  6071. } else if(bx>10.0) {
  6072. use_format="%.1f";
  6073. } else if (bx>1.0) {
  6074. use_format="%.2f";
  6075. } else if (bx>0.1) {
  6076. use_format="%.3f";
  6077. } else if (bx>0.01) {
  6078. use_format="%.4f";
  6079. } else if (bx>0.001) {
  6080. use_format="%.5f";
  6081. } else if (bx>0.0001) {
  6082. use_format="%.6f";
  6083. } else {
  6084. use_format="%g";
  6085. }
  6086. sprintf(newstring,use_format,ax);
  6087. return Tcl_NewStringObj(newstring,-1);
  6088. }
  6089. /* ODIE_Fuzzy_Compare */
  6090. inline extern int ODIE_Fuzzy_Compare(double avalue,double bvalue,double epsilon){
  6091. /* Handle the simple cases */
  6092. int expa,expb;
  6093. double siga,sigb;
  6094. double c;
  6095. siga=frexp(avalue,&expa);
  6096. sigb=frexp(bvalue,&expb);
  6097. if(expa==expb) {
  6098. c=bvalue-avalue;
  6099. if(fabs(c)<epsilon) {
  6100. return 0;
  6101. }
  6102. }
  6103. if(avalue>bvalue) return 1;
  6104. return -1;
  6105. }
  6106. /* ODIE_Fuzzy_GTE */
  6107. inline extern int ODIE_Fuzzy_GTE(double avalue,double bvalue){
  6108. /* Handle the simple cases */
  6109. if (avalue==bvalue) return 1;
  6110. if (avalue<=ODIE_REAL_TOLERANCE && bvalue>ODIE_REAL_TOLERANCE) return 0;
  6111. if (avalue>bvalue) return 1;
  6112.  
  6113. /* Add epsilon to the send */
  6114. avalue+=ODIE_REAL_TOLERANCE;
  6115. if (avalue>=bvalue) return 2;
  6116.  
  6117. /* For large quantities, loose the decimal points
  6118. if(avalue>100.0 && bvalue>100.0) {
  6119. avalue=ceil(avalue);
  6120. bvalue=floor(bvalue);
  6121. if (avalue>=bvalue) return 2;
  6122. }
  6123. */
  6124. return 0;
  6125. }
  6126. /*
  6127. ** This file implements code for braking up compartment floorplans
  6128. ** into triangles.
  6129. **
  6130. ** A floorplan is defined by vectors (x0,y0,x1,y1) which define the
  6131. ** parameter of each compartment. The interior of the compartment
  6132. ** is always to the right of the vector. Thus the outer boundary
  6133. ** of the compartment rotates clockwise when viewed from above.
  6134. ** Compartments may contain holes which are interior voids surrounded
  6135. ** by counter-clockwise rotating boundaries.
  6136. */
  6137.  
  6138.  
  6139. /*
  6140. ** Compute a hash on a point.
  6141. */
  6142. static int hashTriagPoint(TriagPoint *p){
  6143. int iTX = p->x/OdieGrain;
  6144. int iTY = p->y/OdieGrain;
  6145. return hashInt(iTX+iTY);
  6146. }
  6147.  
  6148. /*
  6149. ** Return TRUE if A is the same point as B.
  6150. */
  6151. static int sameTriagPoint(TriagPoint *A, TriagPoint *B){
  6152. return floatCompare(A->x,B->x)==0 && floatCompare(A->y,B->y)==0;
  6153. }
  6154.  
  6155.  
  6156. #if 0
  6157. /*
  6158. ** Print all vectors in the TriagSegSet. Used for debugging purposes only.
  6159. */
  6160. static void SegPrint(TriagSegment *p, const char *zText){
  6161. printf("%s ", zText);
  6162. if( p ){
  6163. printf("%g,%g -> %g,%g\n", p->from.x, p->from.y, p->to.x, p->to.y);
  6164. }else{
  6165. printf(" (null)\n");
  6166. }
  6167. }
  6168. static void TriagSegSetPrint(TriagSegSet *pSet){
  6169. Link *pLink;
  6170. printf("%d vectors:\n", pSet->nSeg);
  6171. for(pLink=pSet->pAll; pLink; pLink=pLink->pNext){
  6172. SegPrint(pLink->pLinkNode, " ");
  6173. }
  6174. }
  6175. #endif
  6176.  
  6177. /*
  6178. ** Add a new segment to the set
  6179. */
  6180. static TriagSegment *TriagSegSetInsert(
  6181. TriagSegSet *pSet,
  6182. double x0,
  6183. double y0,
  6184. double x1,
  6185. double y1,
  6186. u8 isBoundary
  6187. ){
  6188. int h;
  6189. if(pSet==NULL) {
  6190. return NULL;
  6191. }
  6192. TriagSegment *p = (TriagSegment *)Odie_Alloc( sizeof(*p) );
  6193. memset(p,0,sizeof(*p));
  6194. x0=round(x0);
  6195. y0=round(y0);
  6196. x1=round(x1);
  6197. y1=round(y1);
  6198. if( p==0 ) {
  6199. return NULL;
  6200. }
  6201. p->from.x = x0;
  6202. p->from.y = y0;
  6203. p->to.x = x1;
  6204. p->to.y = y1;
  6205. if( sameTriagPoint(&p->from, &p->to) ){
  6206. Odie_Free((char *)p);
  6207. return NULL;
  6208. }
  6209. p->isBoundary = isBoundary;
  6210. p->notOblique = 0;
  6211.  
  6212. LinkInit(p->all, p);
  6213. LinkInit(p->tmp, p);
  6214. LinkInit(p->orig, p);
  6215. LinkInsert(&pSet->pAll, &p->all);
  6216. h = hashTriagPoint(&p->from);
  6217. LinkInsert(&pSet->aHash[h], &p->orig);
  6218. pSet->nSeg++;
  6219. pSet->pCurrent = p;
  6220. return p;
  6221. }
  6222.  
  6223. /*
  6224. ** Remove a segment from the segment set
  6225. */
  6226. static void TriagSegSetRemove(TriagSegSet *pSet, TriagSegment *p){
  6227. LinkRemove(&p->all);
  6228. LinkRemove(&p->orig);
  6229. pSet->nSeg--;
  6230. if( pSet->pCurrent==p ){
  6231. pSet->pCurrent = pSet->pAll ? pSet->pAll->pLinkNode : 0;
  6232. }
  6233. }
  6234.  
  6235. /*
  6236. ** Call this routine to relink into a segment when the
  6237. ** Seg.from vector changes.
  6238. */
  6239. static void TriagSegRelink(TriagSegSet *pSet, TriagSegment *p){
  6240. int h;
  6241. LinkRemove(&p->orig);
  6242. h = hashTriagPoint(&p->from);
  6243. LinkInsert(&pSet->aHash[h], &p->orig);
  6244. }
  6245.  
  6246. /*
  6247. ** Remove all segments from a segment set
  6248. */
  6249. static void TriagSegSetClear(TriagSegSet *pSet){
  6250. while( pSet->pAll ){
  6251. TriagSegment *p;
  6252. assert( pSet->nSeg>0 );
  6253. p=pSet->pAll->pLinkNode;
  6254. TriagSegSetRemove(pSet, p);
  6255. Odie_Free((char *)p);
  6256. }
  6257. assert( pSet->nSeg==0 );
  6258. }
  6259.  
  6260. #if 0
  6261. /*
  6262. ** Advance the pSet->pAll pointer so that it is pointing to a different
  6263. ** segment.
  6264. */
  6265. static void TriagSegSetStep(TriagSegSet *pSet){
  6266. if( pSet->pCurrent ){
  6267. Link *pNext = pSet->pCurrent->all.pNext;
  6268. pSet->pCurrent = pNext ? pNext->pSeg : 0;
  6269. }
  6270. if( pSet->pCurrent==0 ){
  6271. pSet->pCurrent = pSet->pAll ? pSet->pAll->pSeg : 0;
  6272. }
  6273. }
  6274. #endif
  6275.  
  6276.  
  6277. static inline double Dot_Product(TriagPoint *A, TriagPoint *B, TriagPoint *P){
  6278. double r = (A->y-B->y)*(P->x-B->x) + (B->x-A->x)*(P->y-B->y);
  6279. if(fabs(r) < IRM_EPSILON ) {
  6280. return 0.0;
  6281. }
  6282. return r;
  6283. }
  6284.  
  6285. /*
  6286. ** Consider traveling from point A to B to P. If you have to make
  6287. ** a left-turn at B, then this routine returns -1. If P is on the
  6288. ** same line as A and B then return 0. If you make a right turn
  6289. ** at B in order to reach P then return +1.
  6290. */
  6291. static inline int rightOf(TriagPoint *A, TriagPoint *B, TriagPoint *P){
  6292. /* Algorithm: Rotate AB 90 degrees counter-clockwise. Take
  6293. ** the dot product with BP. The dot produce will be the product
  6294. ** of two (non-negative) magnitudes and the cosine of the angle. So if
  6295. ** the dot product is positive, the bend is to the left, or to the right if
  6296. ** the dot product is negative.
  6297. */
  6298. double r = (A->y-B->y)*(P->x-B->x) + (B->x-A->x)*(P->y-B->y);
  6299. if(fabs(r) < IRM_EPSILON ) {
  6300. return 0;
  6301. }
  6302. if(r>0.0) {
  6303. return -1;
  6304. }
  6305. return 1;
  6306. //return r<0.0 ? +1 : (r>0.0 ? -1 : 0);
  6307. }
  6308.  
  6309. /*
  6310. ** This is a variation on rightOf(). Return 0 only if BP is a continuation
  6311. ** of the line AB. If BP doubles back on AB then return -1.
  6312. */
  6313. static inline int strictlyRightOf(TriagPoint *A, TriagPoint *B, TriagPoint *P){
  6314. int c = rightOf(A,B,P);
  6315. if( c==0 ){
  6316. double r = (A->x-B->x)*(P->x-B->x) + (A->y-B->y)*(P->y-B->y);
  6317. c = r<0.0 ? +1 : -1;
  6318. }
  6319. return c;
  6320. }
  6321.  
  6322. /*
  6323. ** Return TRUE if segments AB and CD intersect
  6324. */
  6325. static int intersect(TriagPoint *A, TriagPoint *B, TriagPoint *C, TriagPoint *D){
  6326. return
  6327. rightOf(A,B,C)*rightOf(A,B,D)<0 &&
  6328. rightOf(C,D,A)*rightOf(C,D,B)<0;
  6329. }
  6330.  
  6331. /*
  6332. ** Return the squared distance between two points.
  6333. */
  6334. static double dist2(TriagPoint *A, TriagPoint *B){
  6335. double dx = B->x - A->x;
  6336. double dy = B->y - A->y;
  6337. return dx*dx + dy*dy;
  6338. }
  6339.  
  6340. /*
  6341. ** Compute angle ABC measured counter-clockwise from AB. Return the
  6342. ** result.
  6343. **
  6344. ** This does not need to be a true angular measure as long as it is
  6345. ** monotonically increasing.
  6346. */
  6347. static double angleOf(TriagPoint *A, TriagPoint *B, TriagPoint *C){
  6348. double a1, a2, a3;
  6349. if( sameTriagPoint(A,C) ){
  6350. return M_PI;
  6351. }
  6352. a1 = atan2(B->y - A->y, B->x - A->x);
  6353. a2 = atan2(C->y - B->y, C->x - B->x);
  6354. a3 = a2-a1;
  6355. if( a3>M_PI ) a3 -= 2.0*M_PI;
  6356. if( a3<=-M_PI ) a3 += 2.0*M_PI;
  6357. return a3;
  6358. }
  6359.  
  6360. static inline double idealAngle(TriagPoint *A, TriagPoint *B, TriagPoint *P){
  6361. double theta = angleOf(A,B,P);
  6362. double d = M_PI*0.25 - theta;
  6363. if(ODIE_Real_Is_Zero(d)) {
  6364. return 0.0;
  6365. }
  6366. return d;
  6367. }
  6368.  
  6369. /*
  6370. ** Given line segment AB, locate segment BC and return a pointer to
  6371. ** it. If there is not BC return NULL. If there is more than one
  6372. ** BC return the one that minimizes the angle ABC.
  6373. */
  6374. static TriagSegment *TriagSegSetNext(TriagSegSet *pSet, TriagSegment *pAB){
  6375. Link *pX;
  6376. TriagSegment *pBest = 0;
  6377. double angle, bestAngle;
  6378. int cnt = 0;
  6379. int h;
  6380. h = hashTriagPoint(&pAB->to);
  6381. for(pX=pSet->aHash[h]; pX; pX=pX->pNext){
  6382. TriagSegment *pSeg = pX->pLinkNode;
  6383. if( !sameTriagPoint(&pSeg->from, &pAB->to) ) continue;
  6384. /* if(pAB->isBoundary > 1 && pSeg->isBoundary!=0 && pSeg->isBoundary!=pAB->isBoundary) continue; */
  6385. if( cnt==0 ){
  6386. pBest = pSeg;
  6387. bestAngle = angleOf(&pAB->from, &pAB->to, &pBest->to);
  6388. }else{
  6389. angle = angleOf(&pAB->from, &pAB->to, &pSeg->to);
  6390. if( angle<bestAngle ){
  6391. bestAngle = angle;
  6392. pBest = pSeg;
  6393. }
  6394. }
  6395. cnt++;
  6396. }
  6397. return pBest;
  6398. }
  6399.  
  6400. /*
  6401. ** Find and return the line segment that goes from A to B. Return NULL
  6402. ** if there is not such line segment
  6403. */
  6404. static TriagSegment *TriagSegSetFind(TriagSegSet *pSet, TriagPoint *A, TriagPoint *B){
  6405. Link *pX;
  6406. TriagSegment *p;
  6407. int h;
  6408. h = hashTriagPoint(A);
  6409. for(pX=pSet->aHash[h]; pX; pX=pX->pNext){
  6410. p = pX->pLinkNode;
  6411. if( sameTriagPoint(&p->from, A) && sameTriagPoint(&p->to, B) ){
  6412. return p;
  6413. }
  6414. }
  6415. return 0;
  6416. }
  6417.  
  6418. /*
  6419. ** Remove all segments whose length is less than minLength. For
  6420. ** each segment removed, coalesce the inputs into a single new
  6421. ** point at the center of the segment.
  6422. */
  6423. static void removeShortTriagSegments(TriagSegSet *pSet, double minLength){
  6424. Link *pLoop, *pNext;
  6425. double minLen2;
  6426.  
  6427. minLen2 = minLength*minLength;
  6428. for(pLoop=pSet->pAll; pLoop; pLoop=pNext){
  6429. TriagSegment *p;
  6430. TriagPoint from, to, center;
  6431.  
  6432. p = pLoop->pLinkNode;
  6433. pNext = pLoop->pNext;
  6434. if( dist2(&p->from, &p->to)<minLen2 ){
  6435. from = p->from;
  6436. to = p->to;
  6437. center.x = rint(0.5*(from.x + to.x));
  6438. center.y = rint(0.5*(from.y + to.y));
  6439. TriagSegSetRemove(pSet, p);
  6440. Odie_Free((char *)p);
  6441. for(pLoop=pSet->pAll; pLoop; pLoop=pNext){
  6442. pNext = pLoop->pNext;
  6443. p = pLoop->pLinkNode;
  6444. if( (p->to.x==from.x && p->to.y==from.y)
  6445. || (p->to.x==to.x && p->to.y==to.y)
  6446. ){
  6447. p->to = center;
  6448. }
  6449. if( (p->from.x==from.x && p->from.y==from.y)
  6450. || (p->from.x==to.x && p->from.y==to.y)
  6451. ){
  6452. p->from = center;
  6453. TriagSegRelink(pSet, p);
  6454. }
  6455. if( p->from.x==p->to.x && p->from.y==p->to.y ){
  6456. TriagSegSetRemove(pSet, p);
  6457. Odie_Free((char *)p);
  6458. }
  6459. }
  6460. pNext = pSet->pAll;
  6461. }
  6462. }
  6463. }
  6464.  
  6465. static int WalkTriagSegments(TriagSegSet *pSet) {
  6466. Link *pLoop, *pNext;
  6467. int changed=0;
  6468. for(pLoop=pSet->pAll; pLoop; pLoop=pNext){
  6469. TriagSegment *pAB, *pBC;
  6470. Link *pRight, *pL2;
  6471. int c;
  6472. /* Find an oblique angle ABC */
  6473. pAB = pLoop->pLinkNode;
  6474. pNext = pLoop->pNext;
  6475.  
  6476. /*
  6477. ** If we are at an oblique for a non boundary
  6478. ** segment, continue
  6479. */
  6480. if( pAB->notOblique ) continue;
  6481. pBC = TriagSegSetNext(pSet, pAB);
  6482. if( pBC==0 ) {
  6483. /*
  6484. ** Remove an orphan wall
  6485. */
  6486. TriagSegSetRemove(pSet, pAB);
  6487. Odie_Free((char *)pAB);
  6488. changed=1;
  6489. continue;
  6490. }
  6491.  
  6492. if( (c = rightOf(&pAB->from, &pAB->to, &pBC->to))>=0 ){
  6493. if( c>0 || !sameTriagPoint(&pAB->from, &pBC->to) ){
  6494. pAB->notOblique = 1;
  6495. continue;
  6496. }
  6497. }
  6498.  
  6499. /* If we reach here, it means that ABC is an oblique angle.
  6500. ** Locate all vertices to the right of AB.
  6501. */
  6502. pRight = 0;
  6503. for(pL2=pSet->pAll; pL2; pL2=pL2->pNext){
  6504. TriagSegment *pX = pL2->pLinkNode;
  6505. if( strictlyRightOf(&pAB->from, &pAB->to, &pX->from)<0 ) continue;
  6506. if( sameTriagPoint(&pAB->to, &pX->from) ) continue;
  6507. pX->score = dist2(&pAB->to, &pX->from);
  6508. pX->isRight = rightOf(&pBC->from, &pBC->to, &pX->from);
  6509. LinkInit(pX->tmp, pX);
  6510. LinkInsert(&pRight, &pX->tmp);
  6511. }
  6512. if( pRight==0 ){
  6513. return TCL_ERROR;
  6514. }
  6515.  
  6516. /* pRight is a list of vertices to the right of AB. Find the
  6517. ** closest vertex X on this list where the line BX does not intersect
  6518. ** any other segment in the polygon. Then add segments BX and XB.
  6519. */
  6520. while( pRight ){
  6521. Link *pBest=NULL;
  6522. double bestScore;
  6523. int bestRight;
  6524. TriagSegment *pThis,*pX, *pQ;
  6525.  
  6526.  
  6527. /* Search for the "best" vertex. The best vertex is the
  6528. ** one that is closest. Though if the vertex is to the left
  6529. ** of BC (and thus would create another oblique angle) then
  6530. ** artificially reduce its score because we would prefer not
  6531. ** to use it.
  6532. */
  6533. pBest = pRight;
  6534. pThis=pBest->pLinkNode;
  6535. bestScore = pThis->score;
  6536. bestRight = pThis->isRight;
  6537. for(pL2=pBest->pNext; pL2; pL2=pL2->pNext){
  6538. int better=0;
  6539. pX = pL2->pLinkNode;
  6540. if( pX->isRight>0 && bestRight <=0 ) {
  6541. better=1;
  6542. } else if ( pX->isRight<=0 && bestRight>0 ) {
  6543. better=0;
  6544. } else if( pX->score<bestScore ){
  6545. better=1;
  6546. }
  6547. if(better) {
  6548. bestScore = pX->score;
  6549. bestRight = pX->isRight;
  6550. pBest = pL2;
  6551. }
  6552. }
  6553.  
  6554. /* The best vertex is pX */
  6555. pX = pBest->pLinkNode;
  6556. LinkRemove(pBest);
  6557.  
  6558. /* Check to see if BX intersects any segment. If it does, then
  6559. ** go back and search for a different X
  6560. */
  6561. for(pL2=pSet->pAll; pL2; pL2=pL2->pNext){
  6562. pQ = pL2->pLinkNode;
  6563. if( pQ!=pAB && pQ!=pX
  6564. && intersect(&pAB->to, &pX->from, &pQ->from, &pQ->to) ){
  6565. break;
  6566. }
  6567. }
  6568. if( pL2 ) continue;
  6569.  
  6570. /* It did not intersect. So add BX and XB to the pSet->
  6571. */
  6572. TriagSegSetInsert(pSet, pAB->to.x, pAB->to.y, pX->from.x, pX->from.y, 0);
  6573. TriagSegSetInsert(pSet, pX->from.x, pX->from.y, pAB->to.x, pAB->to.y, 0);
  6574. pRight = 0;
  6575. }
  6576. changed=1;
  6577. if(!pAB->isBoundary) {
  6578. pNext = pSet->pAll;
  6579. }
  6580. }
  6581. if(changed) {
  6582. return TCL_CONTINUE;
  6583. }
  6584. return TCL_OK;
  6585. }
  6586.  
  6587. /*
  6588. ** tclcmd: convex_subpolygons_new VECTORS ?MINLENGTH? ?HOLE? ?HOLE? ...
  6589. **
  6590. ** VECTORS is a list of floating-point values. Each group of four values
  6591. ** forms a vector X0,Y0->X1,Y1. The vectors are in no particular order,
  6592. ** but together they form one or more loops. Space to the right of each
  6593. ** vector is within the loop and space to the left is outside.
  6594. **
  6595. ** Loops can be nested. The outer boundary is formed by a clockwise loop
  6596. ** of vectors. Interior holes are formed by counter-clockwise loops.
  6597. **
  6598. ** The output is a list polygons. Each polygon is a list of 3 or more
  6599. ** X,Y coordinate pairs. All polygons are convex and disjoint and they
  6600. ** together cover the input polygon.
  6601. **
  6602. ** Optionally, the user can specify a series of polygons to be subtracted
  6603. ** from the main polygon. These are given as an XY list suitable for
  6604. ** producing a polygon on the tkcanvas
  6605. */
  6606. static int convexNewSubpolyCmd(
  6607. void *pArg,
  6608. Tcl_Interp *interp,
  6609. int objc,
  6610. Tcl_Obj *CONST objv[]
  6611. ){
  6612. Tcl_Obj *pOut; /* The output list */
  6613. Tcl_Obj *pSub; /* A sublist for a single polygon */
  6614. int i, idx, n, nb, cnt;
  6615. TriagSegSet set;
  6616. double minLen = 0.0;
  6617.  
  6618. if( objc!=2 && objc!=3 && objc<4 ){
  6619. Tcl_WrongNumArgs(interp, 1, objv, "VECTORS ?MINLENGTH? ?HOLE? ?HOLE? ...");
  6620. return TCL_ERROR;
  6621. }
  6622. if( Tcl_ListObjLength(interp, objv[1], &n) ) return TCL_ERROR;
  6623. if( objc>2 ){
  6624. if( Tcl_GetDoubleFromObj(interp, objv[2], &minLen) ) return TCL_ERROR;
  6625. }
  6626. if( n<12 || n%4!=0 ){
  6627. Tcl_AppendResult(interp, "VECTORS argument should contain at least 12 and "
  6628. " a multiple of 4 values", 0);
  6629. return TCL_ERROR;
  6630. }
  6631. memset(&set, 0, sizeof(set));
  6632.  
  6633. /*
  6634. ** Insert the polygons the user specified as
  6635. ** the shape of the holes first
  6636. */
  6637. for(idx=3;idx<objc;idx++) {
  6638. double fx,fy,px,py;
  6639.  
  6640. if( Tcl_ListObjLength(interp, objv[idx], &nb) ) return TCL_ERROR;
  6641. if( nb > 0 && (nb<6 || nb%2!=0) ){
  6642. TriagSegSetClear(&set);
  6643. Tcl_AppendResult(interp, "HOLES arguments should contain at least 6 and "
  6644. " a multiple of 2 values", 0);
  6645. return TCL_ERROR;
  6646. }
  6647. Tcl_Obj *pObj;
  6648. Tcl_ListObjIndex(0, objv[idx], 0, &pObj);
  6649. if( Tcl_GetDoubleFromObj(interp, pObj, &fx) ){
  6650. TriagSegSetClear(&set);
  6651. return TCL_ERROR;
  6652. }
  6653. Tcl_ListObjIndex(0, objv[idx], 1, &pObj);
  6654. if( Tcl_GetDoubleFromObj(interp, pObj, &fy) ){
  6655. TriagSegSetClear(&set);
  6656. return TCL_ERROR;
  6657. }
  6658. px=fx;
  6659. py=fy;
  6660. for(i=2; i<nb; i+=2){
  6661. double mx,my;
  6662. double nx,ny;
  6663. Tcl_ListObjIndex(0, objv[idx], i, &pObj);
  6664. if( Tcl_GetDoubleFromObj(interp, pObj, &nx) ){
  6665. TriagSegSetClear(&set);
  6666. return TCL_ERROR;
  6667. }
  6668. Tcl_ListObjIndex(0, objv[idx], i+1, &pObj);
  6669. if( Tcl_GetDoubleFromObj(interp, pObj, &ny) ){
  6670. TriagSegSetClear(&set);
  6671. return TCL_ERROR;
  6672. }
  6673. /*
  6674. TriagSegSetInsert(&set, px, py, nx, ny, idx);
  6675. */
  6676. mx=(nx+px)/2.0;
  6677. my=(ny+py)/2.0;
  6678.  
  6679. TriagSegSetInsert(&set, px, py, mx, my, idx);
  6680. TriagSegSetInsert(&set, mx, my, nx, ny, idx);
  6681. px=nx;
  6682. py=ny;
  6683. }
  6684. double mx,my;
  6685. mx=(fx+px)/2.0;
  6686. my=(fy+py)/2.0;
  6687. TriagSegSetInsert(&set, px, py, mx, my, idx);
  6688. TriagSegSetInsert(&set, mx, my, fx, fy, idx);
  6689. }
  6690.  
  6691. for(i=0; i<n; i+=4){
  6692. int j;
  6693. double x[4];
  6694. TriagPoint A,B,C;
  6695. for(j=0; j<4; j++){
  6696. Tcl_Obj *pObj;
  6697. Tcl_ListObjIndex(0, objv[1], i+j, &pObj);
  6698. if( Odie_GetMatrixElementFromObj(interp, pObj, x, j) ){
  6699. TriagSegSetClear(&set);
  6700. return TCL_ERROR;
  6701. }
  6702. }
  6703. A.x=x[0];
  6704. A.y=x[1];
  6705. C.x=x[2];
  6706. C.y=x[3];
  6707. B.x=(C.x+A.x)/2.0;
  6708. B.y=(C.y+A.y)/2.0;
  6709.  
  6710. /*
  6711. ** Do not insert a vector into the wallset if it
  6712. ** matches a vector already given. It's either redundent
  6713. ** or the edge of a hole
  6714. */
  6715. if(!TriagSegSetFind(&set,&A,&C)) {
  6716. TriagSegSetInsert(&set, A.x, A.y, B.x, B.y, 1);
  6717. }
  6718. if(!TriagSegSetFind(&set,&B,&C)) {
  6719. TriagSegSetInsert(&set, B.x, B.y, C.x, C.y, 1);
  6720. }
  6721. }
  6722.  
  6723. if( minLen>0.0 ){
  6724. removeShortTriagSegments(&set, minLen);
  6725. }
  6726.  
  6727. cnt=0;
  6728. i=TCL_CONTINUE;
  6729. while(i==TCL_CONTINUE) {
  6730. i=WalkTriagSegments(&set);
  6731. cnt++;
  6732. if(cnt>10) {
  6733. break;
  6734. }
  6735. }
  6736. if(i==TCL_CONTINUE) {
  6737. Tcl_AppendResult(interp, "boundary too complex", 0);
  6738. TriagSegSetClear(&set);
  6739. return TCL_ERROR;
  6740. }
  6741. if(i==TCL_ERROR) {
  6742. Tcl_AppendResult(interp, "boundary does not enclose a finite space", 0);
  6743. TriagSegSetClear(&set);
  6744. return TCL_ERROR;
  6745. }
  6746.  
  6747. /* Now all polygons should be convex. We just have to generate them. */
  6748. pOut = Tcl_NewObj();
  6749. int npoly=0;
  6750. while( set.nSeg ){
  6751. TriagPoint start;
  6752. TriagSegment *pAB, *pBC;
  6753. int valid = 0;
  6754. int cnt = 0;
  6755. npoly++;
  6756.  
  6757. pAB = set.pAll->pLinkNode;
  6758. start = pAB->from;
  6759. /*
  6760. ** Walk along the wallsets, filter out
  6761. ** any that do not include one of the
  6762. ** vectors given as an input of the first
  6763. ** argument
  6764. */
  6765. pSub = Tcl_NewObj();
  6766. while( pAB ){
  6767. Tcl_ListObjAppendElement(0, pSub, Tcl_NewDoubleObj(pAB->to.x));
  6768. Tcl_ListObjAppendElement(0, pSub, Tcl_NewDoubleObj(pAB->to.y));
  6769. if(pAB->isBoundary < 2) valid=1;
  6770. cnt++;
  6771. TriagSegSetRemove(&set, pAB);
  6772. if( sameTriagPoint(&pAB->to, &start) ) {
  6773. break;
  6774. }
  6775. pBC = TriagSegSetNext(&set, pAB);
  6776. Odie_Free((char *)pAB);
  6777. pAB = pBC;
  6778. }
  6779. if( pAB==0 || cnt<3 || !valid){
  6780. Tcl_DecrRefCount(pSub);
  6781. }else{
  6782. Tcl_ListObjAppendElement(0, pOut, pSub);
  6783. }
  6784. }
  6785. TriagSegSetClear(&set);
  6786. Tcl_SetObjResult(interp, pOut);
  6787. return TCL_OK;
  6788. }
  6789.  
  6790.  
  6791. /*
  6792. ** tclcmd: convex_subpolygons VECTORS ?MINLENGTH? ?HOLE? ?HOLE? ...
  6793. **
  6794. ** VECTORS is a list of floating-point values. Each group of four values
  6795. ** forms a vector X0,Y0->X1,Y1. The vectors are in no particular order,
  6796. ** but together they form one or more loops. Space to the right of each
  6797. ** vector is within the loop and space to the left is outside.
  6798. **
  6799. ** Loops can be nested. The outer boundary is formed by a clockwise loop
  6800. ** of vectors. Interior holes are formed by counter-clockwise loops.
  6801. **
  6802. ** The output is a list polygons. Each polygon is a list of 3 or more
  6803. ** X,Y coordinate pairs. All polygons are convex and disjoint and they
  6804. ** together cover the input polygon.
  6805. **
  6806. ** Optionally, the user can specify a series of polygons to be subtracted
  6807. ** from the main polygon. These are given as an XY list suitable for
  6808. ** producing a polygon on the tkcanvas
  6809. */
  6810. static int convexSubpolyCmd(
  6811. void *pArg,
  6812. Tcl_Interp *interp,
  6813. int objc,
  6814. Tcl_Obj *CONST objv[]
  6815. ){
  6816. Tcl_Obj *pOut; /* The output list */
  6817. Tcl_Obj *pSub; /* A sublist for a single polygon */
  6818. int i, idx, n, nb, cnt;
  6819. TriagSegSet set;
  6820. double minLen = 0.0;
  6821.  
  6822. if( objc!=2 && objc!=3 && objc<4 ){
  6823. Tcl_WrongNumArgs(interp, 1, objv, "VECTORS ?MINLENGTH? ?HOLE? ?HOLE? ...");
  6824. return TCL_ERROR;
  6825. }
  6826. if( Tcl_ListObjLength(interp, objv[1], &n) ) return TCL_ERROR;
  6827. if( objc>2 ){
  6828. if( Tcl_GetDoubleFromObj(interp, objv[2], &minLen) ) return TCL_ERROR;
  6829. }
  6830. if( n<12 || n%4!=0 ){
  6831. Tcl_AppendResult(interp, "VECTORS argument should contain at least 12 and "
  6832. " a multiple of 4 values", 0);
  6833. return TCL_ERROR;
  6834. }
  6835. memset(&set, 0, sizeof(set));
  6836.  
  6837. /*
  6838. ** Insert the polygons the user specified as
  6839. ** the shape of the holes first
  6840. */
  6841. for(idx=3;idx<objc;idx++) {
  6842. double fx,fy,px,py;
  6843.  
  6844. if( Tcl_ListObjLength(interp, objv[idx], &nb) ) return TCL_ERROR;
  6845. if( nb > 0 && (nb<6 || nb%2!=0) ){
  6846. TriagSegSetClear(&set);
  6847. Tcl_AppendResult(interp, "HOLES arguments should contain at least 6 and "
  6848. " a multiple of 2 values", 0);
  6849. return TCL_ERROR;
  6850. }
  6851. Tcl_Obj *pObj;
  6852. Tcl_ListObjIndex(0, objv[idx], 0, &pObj);
  6853. if( Tcl_GetDoubleFromObj(interp, pObj, &fx) ){
  6854. TriagSegSetClear(&set);
  6855. return TCL_ERROR;
  6856. }
  6857. Tcl_ListObjIndex(0, objv[idx], 1, &pObj);
  6858. if( Tcl_GetDoubleFromObj(interp, pObj, &fy) ){
  6859. TriagSegSetClear(&set);
  6860. return TCL_ERROR;
  6861. }
  6862. px=fx;
  6863. py=fy;
  6864. for(i=2; i<nb; i+=2){
  6865. double nx,ny;
  6866. Tcl_ListObjIndex(0, objv[idx], i, &pObj);
  6867. if( Tcl_GetDoubleFromObj(interp, pObj, &nx) ){
  6868. TriagSegSetClear(&set);
  6869. return TCL_ERROR;
  6870. }
  6871. Tcl_ListObjIndex(0, objv[idx], i+1, &pObj);
  6872. if( Tcl_GetDoubleFromObj(interp, pObj, &ny) ){
  6873. TriagSegSetClear(&set);
  6874. return TCL_ERROR;
  6875. }
  6876. TriagSegSetInsert(&set, px, py, nx, ny, idx);
  6877. px=nx;
  6878. py=ny;
  6879. }
  6880. TriagSegSetInsert(&set, px, py, fx, fy, idx);
  6881. }
  6882.  
  6883. for(i=0; i<n; i+=4){
  6884. int j;
  6885. double x[4];
  6886. TriagPoint A,B;
  6887. for(j=0; j<4; j++){
  6888. Tcl_Obj *pObj;
  6889. Tcl_ListObjIndex(0, objv[1], i+j, &pObj);
  6890. if( Odie_GetMatrixElementFromObj(interp, pObj, x, j) ){
  6891. TriagSegSetClear(&set);
  6892. return TCL_ERROR;
  6893. }
  6894. }
  6895. A.x=x[0];
  6896. A.y=x[1];
  6897. B.x=x[2];
  6898. B.y=x[3];
  6899. /*
  6900. ** Do not insert a vector into the wallset if it
  6901. ** matches a vector already given. It's either redundent
  6902. ** or the edge of a hole
  6903. */
  6904. if(TriagSegSetFind(&set,&A,&B)) continue;
  6905. TriagSegSetInsert(&set, x[0], x[1], x[2], x[3], 1);
  6906. }
  6907.  
  6908. if( minLen>0.0 ){
  6909. removeShortTriagSegments(&set, minLen);
  6910. }
  6911.  
  6912. cnt=0;
  6913. i=TCL_CONTINUE;
  6914. while(i==TCL_CONTINUE) {
  6915. i=WalkTriagSegments(&set);
  6916. cnt++;
  6917. if(cnt>10) {
  6918. break;
  6919. }
  6920. }
  6921. if(i==TCL_CONTINUE) {
  6922. Tcl_AppendResult(interp, "{boundary too complex}", 0);
  6923. TriagSegSetClear(&set);
  6924. return TCL_ERROR;
  6925. }
  6926. if(i==TCL_ERROR) {
  6927. Tcl_AppendResult(interp, "{boundary does not enclose a finite space}", 0);
  6928. TriagSegSetClear(&set);
  6929. return TCL_ERROR;
  6930. }
  6931.  
  6932. int obtuseangles=0;
  6933. /* Now all polygons should be convex. We just have to generate them. */
  6934. pOut = Tcl_NewObj();
  6935. while( set.nSeg ){
  6936. TriagPoint start;
  6937. TriagSegment *pAB, *pBC;
  6938. int valid = 0;
  6939. int cnt = 0;
  6940.  
  6941. pAB = set.pAll->pLinkNode;
  6942. start = pAB->from;
  6943. /*
  6944. ** Walk along the wallsets, filter out
  6945. ** any that do not include one of the
  6946. ** vectors given as an input of the first
  6947. ** argument
  6948. */
  6949. pSub = Tcl_NewObj();
  6950. while( pAB ){
  6951. Tcl_ListObjAppendElement(0, pSub, Tcl_NewDoubleObj(pAB->to.x));
  6952. Tcl_ListObjAppendElement(0, pSub, Tcl_NewDoubleObj(pAB->to.y));
  6953. pBC = TriagSegSetNext(&set, pAB);
  6954. if(pAB->isBoundary < 2) valid=1;
  6955. if(pAB->isRight<0) obtuseangles++;
  6956. cnt++;
  6957. TriagSegSetRemove(&set, pAB);
  6958. if( sameTriagPoint(&pAB->to, &start) ) {
  6959. break;
  6960. }
  6961. Odie_Free((char *)pAB);
  6962. pAB = pBC;
  6963. }
  6964. if( pAB==0 || cnt<3 || !valid){
  6965. Tcl_DecrRefCount(pSub);
  6966. }else{
  6967. Tcl_ListObjAppendElement(0, pOut, pSub);
  6968. }
  6969. }
  6970. TriagSegSetClear(&set);
  6971. if(obtuseangles) {
  6972. Tcl_DecrRefCount(pOut);
  6973. convexNewSubpolyCmd(NULL,interp,objc,objv);
  6974. } else {
  6975. Tcl_SetObjResult(interp, pOut);
  6976. }
  6977. return TCL_OK;
  6978. }
  6979. /*
  6980. ** This file implements a TCL object used for tracking polygons. A
  6981. ** single new TCL command named "poly" is defined. This command
  6982. ** has methods for creating, deleting, and taking the intersection
  6983. ** of 2-D polygons. There are comments on the implementation of each
  6984. ** method to describe what the method does.
  6985. **
  6986. ** This module was originally developed to aid in computing the
  6987. ** shared surface area between two compartments on separate decks.
  6988. ** The shared surface area is needed in initializing the fire model
  6989. ** since heat conduction between the two compartments is proportional
  6990. ** to their shared area.
  6991. */
  6992. /* PolygonObj_freeIntRepProc */
  6993. void PolygonObj_freeIntRepProc(Tcl_Obj *objPtr){
  6994. if(objPtr->internalRep.otherValuePtr) {
  6995. Odie_Polygon *pPoly=objPtr->internalRep.otherValuePtr;
  6996. if(pPoly->refCount) {
  6997. pPoly->refCount--;
  6998. }
  6999. if(!pPoly->refCount) {
  7000. Tcl_Free(objPtr->internalRep.otherValuePtr);
  7001. objPtr->internalRep.otherValuePtr=NULL;
  7002. objPtr->typePtr=NULL;
  7003. }
  7004. }
  7005. }
  7006. /* PolygonObj_dupIntRepProc */
  7007. void PolygonObj_dupIntRepProc(Tcl_Obj *srcPtr,Tcl_Obj *dupPtr){
  7008. Odie_Polygon *src=srcPtr->internalRep.otherValuePtr;
  7009. int size=sizeof(*src)+src->nVertex*sizeof(src->v[0]);
  7010. Odie_Polygon *copy=(Odie_Polygon *)Odie_Alloc(size);
  7011.  
  7012. memcpy(copy,src,size);
  7013. Tcl_InvalidateStringRep(dupPtr);
  7014. dupPtr->typePtr=&polygon_tclobjtype;
  7015. dupPtr->internalRep.otherValuePtr=copy;
  7016. }
  7017. /* PolygonObj_updateStringRepProc */
  7018. void PolygonObj_updateStringRepProc(Tcl_Obj *objPtr){
  7019. /* Update String Rep */
  7020. char outbuffer[128];
  7021. Tcl_DString result;
  7022. Odie_Polygon *p=objPtr->internalRep.otherValuePtr;
  7023. int i,j;
  7024. Tcl_DStringInit(&result);
  7025. j=p->nVertex-1;
  7026. if(p->v[0][X_IDX]==p->v[j][X_IDX] && p->v[0][Y_IDX]==p->v[j][Y_IDX]) {
  7027. j=p->nVertex-2;
  7028. }
  7029. for(i=0; i<=j; i++){
  7030. sprintf(outbuffer,"%g %g",(float)p->v[i][X_IDX],(float)p->v[i][Y_IDX]);
  7031. Tcl_DStringAppendElement(&result,outbuffer);
  7032. }
  7033. objPtr->length=Tcl_DStringLength(&result);
  7034. objPtr->bytes=Odie_Alloc(objPtr->length+1);
  7035. strcpy(objPtr->bytes,Tcl_DStringValue(&result));
  7036. Tcl_DStringFree(&result);
  7037. }
  7038. /* Odie_Poly_ShimmerOrFree_TclObj */
  7039. int Odie_Poly_ShimmerOrFree_TclObj(Tcl_Obj *objPtr,Odie_Polygon *p){
  7040. if(objPtr->typePtr) {
  7041. if(objPtr->typePtr->setFromAnyProc==&PolygonObj_setFromAnyProc) {
  7042. /*
  7043. ** Object is already of the type requested
  7044. */
  7045. return 1;
  7046. }
  7047. }
  7048. if(Tcl_IsShared(objPtr)) {
  7049. Odie_Free((char *)p);
  7050. return 1;
  7051. }
  7052. if(objPtr->typePtr && objPtr->typePtr->freeIntRepProc) {
  7053. Tcl_FreeInternalRepProc *freeIntRepProc=objPtr->typePtr->freeIntRepProc;
  7054. freeIntRepProc(objPtr);
  7055. }
  7056. objPtr->internalRep.otherValuePtr=p;
  7057. objPtr->typePtr=&polygon_tclobjtype;
  7058. Tcl_IncrRefCount(objPtr);
  7059. return 0;
  7060. }
  7061. /* *Odie_Poly_Create */
  7062. Odie_Polygon *Odie_Poly_Create(int nVertex){
  7063. Odie_Polygon *p;
  7064. p=(Odie_Polygon *)Odie_Alloc(sizeof(*p)+(nVertex+1)*sizeof(p->v[0]));
  7065. p->nVertex=nVertex;
  7066. return p;
  7067. }
  7068. /* PolygonObj_setFromAnyProc */
  7069. int PolygonObj_setFromAnyProc(Tcl_Interp *interp,Tcl_Obj *objPtr){
  7070. /* Set internal rep from any Tcl_Obj */
  7071. if(objPtr->typePtr) {
  7072. if(objPtr->typePtr==&polygon_tclobjtype) {
  7073. /*
  7074. ** Object is already of the type requested
  7075. */
  7076. return TCL_OK;
  7077. }
  7078. }
  7079. Odie_Polygon *p;
  7080. int created=0;
  7081. if(Odie_Polygon_GetFromTclObj(interp,objPtr,&p,&created)) {
  7082. return TCL_ERROR;
  7083. }
  7084. Tcl_InvalidateStringRep(objPtr);
  7085. objPtr->internalRep.otherValuePtr=p;
  7086. objPtr->typePtr=&polygon_tclobjtype;
  7087. return TCL_OK;
  7088. }
  7089. /* *Odie_Polygon_NewTclObj */
  7090. Tcl_Obj *Odie_Polygon_NewTclObj(Odie_Polygon *pPoly){
  7091. Tcl_Obj *pResult;
  7092. pResult=Tcl_NewObj();
  7093. Tcl_InvalidateStringRep(pResult);
  7094. pPoly->refCount++;
  7095. pResult->internalRep.otherValuePtr=pPoly;
  7096. pResult->typePtr=&polygon_tclobjtype;
  7097. return pResult;
  7098. }
  7099. /* Odie_Polygon_From_FaceXYZ */
  7100. int Odie_Polygon_From_FaceXYZ(Tcl_Interp *interp,Tcl_Obj *objPtr,Odie_Polygon **ptr){
  7101. int i,nVertex;
  7102. Tcl_Obj *pElem;
  7103. Odie_Polygon *p;
  7104. Odie_FaceXYZ *poly;
  7105. poly=objPtr->internalRep.otherValuePtr;
  7106. nVertex=poly->nVertex;
  7107. p=Odie_Poly_Create(nVertex);
  7108. for(i=0; i<nVertex; i++){
  7109. VectorXY_Copy(p->v[i],poly->vertex_xyz[i]);
  7110. }
  7111. VectorXY_Copy(p->v[nVertex],poly->vertex_xyz[0]);
  7112.  
  7113. if(Odie_Polygon_ComputeArea(interp,p)) goto createfail;
  7114. *ptr=p;
  7115. return TCL_OK;
  7116.  
  7117. createfail:
  7118. Odie_Free((char *)p);
  7119. return TCL_ERROR;
  7120. }
  7121. /* Odie_Polygon_GetFromTclObj */
  7122. int Odie_Polygon_GetFromTclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,Odie_Polygon **ptr,int *created){
  7123. Odie_Polygon *p;
  7124. *created=0;
  7125.  
  7126. if(objPtr->typePtr) {
  7127. if(objPtr->typePtr==&polygon_tclobjtype && objPtr->internalRep.otherValuePtr) {
  7128. /*
  7129. ** Object is already of the type requested
  7130. */
  7131. *ptr=objPtr->internalRep.otherValuePtr;
  7132. return TCL_OK;
  7133. }
  7134. if(objPtr->typePtr->setFromAnyProc==&Odie_FaceXYZ_setFromAnyProc && objPtr->internalRep.otherValuePtr) {
  7135. *created=1;
  7136. return Odie_Polygon_From_FaceXYZ(interp,objPtr,ptr);
  7137. }
  7138. }
  7139. int k,i;
  7140. if( Tcl_ListObjLength(interp, objPtr, &k) ) return TCL_ERROR;
  7141. if( k<6 ){
  7142. Tcl_AppendResult(interp, "need at least 3 vertices", 0);
  7143. return TCL_ERROR;
  7144. }
  7145. if( k&1 ){
  7146. Tcl_AppendResult(interp, "coordinates should come in pairs", 0);
  7147. return TCL_ERROR;
  7148. }
  7149. *created=1;
  7150. p=(Odie_Polygon *)Odie_Alloc(sizeof(*p)+(k+2)*sizeof(p->v[0]));
  7151. p->nVertex=k/2;
  7152. for(i=0; i<p->nVertex; i++){
  7153. Tcl_Obj *pElem;
  7154. double d;
  7155. Tcl_ListObjIndex(0, objPtr, i*2, &pElem);
  7156. if(Tcl_GetDoubleFromObj(interp, pElem, &d)) goto createfail;
  7157. p->v[i][X_IDX] = d;
  7158. Tcl_ListObjIndex(0, objPtr, i*2+1, &pElem);
  7159. if(Tcl_GetDoubleFromObj(interp, pElem, &d)) goto createfail;
  7160. p->v[i][Y_IDX] = d;
  7161. }
  7162. if(Odie_Polygon_ComputeArea(interp,p)==TCL_OK) {
  7163. *ptr=p;
  7164. return TCL_OK;
  7165. }
  7166.  
  7167. createfail:
  7168. Tcl_Free((char *)p);
  7169. return TCL_ERROR;
  7170. }
  7171. /* Odie_IsColinear */
  7172. static inline int Odie_IsColinear(double x1,double y1,double x2,double y2,double x3,double y3){
  7173. /* Detect of two lines are colinear */
  7174. if(floatCompare(x1,x3)==0 && floatCompare(y1,y3)==0) {
  7175. return 1;
  7176. }
  7177. double c=(x3-x1)*(y2-y1)-(y3-y1)*(x2-x1);
  7178. if(fabs(c) < __FLT_EPSILON__) return 1;
  7179. return 0;
  7180. }
  7181. /* dist */
  7182. static inline double dist(double x0, double y0, double x1, double y1){
  7183. /*
  7184. ** Return the distance between two points
  7185. */
  7186. double dx = x1 - x0;
  7187. double dy = y1 - y0;
  7188. return sqrt(dx*dx + dy*dy);
  7189. }
  7190. /* withinPolygon */
  7191. static inline int withinPolygon(Odie_Polygon *p, double x, double y){
  7192. /*
  7193. ** Return -1, 0, or 1 if the point x,y is outside, on, or within
  7194. ** the polygon p.
  7195. */
  7196. int res, i;
  7197. /* Do a bounding box check before getting more ellaborate */
  7198. if( x>p->bbox[BBOX_X1_IDX]
  7199. || x<p->bbox[BBOX_X0_IDX]
  7200. || y>p->bbox[BBOX_Y1_IDX]
  7201. || y<p->bbox[BBOX_Y0_IDX]
  7202. ) return -1;
  7203. res = -1;
  7204. for(i=0; i<p->nVertex-1; i++){
  7205. double x0, y0, x1, y1, yP;
  7206. x0 = p->v[i][X_IDX];
  7207. y0 = p->v[i][Y_IDX];
  7208. x1 = p->v[i+1][X_IDX];
  7209. y1 = p->v[i+1][Y_IDX];
  7210. if( x0==x1 ){
  7211. if( x0==x && ((y0<=y && y1>=y) || (y1<=y && y0>=y)) ){
  7212. res = 0;
  7213. break;
  7214. }
  7215. continue;
  7216. }
  7217. if( x0>x1 ){
  7218. int t = x0;
  7219. x0 = x1;
  7220. x1 = t;
  7221. t = y0;
  7222. y0 = y1;
  7223. y1 = t;
  7224. }
  7225. if( x>=x1 || x<x0 ) continue;
  7226. yP = y1 - (x1-x)*(y1-y0)/(x1-x0);
  7227. if( yP == y ){ res = 0; break; }
  7228. if( yP > y ){ res = -res; }
  7229. }
  7230. return res;
  7231. }
  7232. /* Odie_Polygon_XYWithin */
  7233. int Odie_Polygon_XYWithin(Odie_Polygon *p, double x, double y){
  7234. /*
  7235. ** Return -1, 0, or 1 if the point x,y is outside, on, or within
  7236. ** the polygon p.
  7237. */
  7238. return withinPolygon(p,x,y);
  7239. }
  7240. /* Odie_Polygon_VectorXYWithin */
  7241. int Odie_Polygon_VectorXYWithin(Odie_Polygon *p, VectorXY C){
  7242. /*
  7243. ** Return -1, 0, or +1 if the point P is outside, on the border of, or
  7244. ** fully contained within the subcompartment pSub.
  7245. */
  7246. return withinPolygon(p,C[X_IDX],C[Y_IDX]);
  7247. }
  7248. /* Odie_Polygon_ComputeArea */
  7249. int Odie_Polygon_ComputeArea(Tcl_Interp *interp,Odie_Polygon *p){
  7250. double area=0.0;
  7251. double areacomp=0.0;
  7252. int i;
  7253.  
  7254. if( p->v[p->nVertex-1][X_IDX]!=p->v[0][X_IDX] || p->v[p->nVertex-1][Y_IDX]!=p->v[0][Y_IDX] ){
  7255. p->v[p->nVertex][X_IDX] = p->v[0][X_IDX];
  7256. p->v[p->nVertex][Y_IDX] = p->v[0][Y_IDX];
  7257. p->nVertex++;
  7258. }
  7259.  
  7260. for(i=0; i<p->nVertex-1; i++){
  7261. area += 0.5*(p->v[i][Y_IDX] + p->v[i+1][Y_IDX])*(p->v[i+1][X_IDX] - p->v[i][X_IDX]);
  7262. }
  7263. if( area<0.0 ){
  7264. int b, e;
  7265. for(b=0, e=p->nVertex-1; b<e; b++, e--){
  7266. double t;
  7267. t = p->v[b][X_IDX];
  7268. p->v[b][X_IDX] = p->v[e][X_IDX];
  7269. p->v[e][X_IDX] = t;
  7270. t = p->v[b][Y_IDX];
  7271. p->v[b][Y_IDX] = p->v[e][Y_IDX];
  7272. p->v[e][Y_IDX] = t;
  7273. }
  7274. area = -area;
  7275. }
  7276. p->area = area;
  7277. p->bbox[BBOX_X0_IDX] = p->bbox[BBOX_X1_IDX] = p->v[0][X_IDX];
  7278. p->bbox[BBOX_Y1_IDX] = p->bbox[BBOX_Y0_IDX] = p->v[0][Y_IDX];
  7279. for(i=1; i<p->nVertex-1; i++){
  7280. double x, y;
  7281. x = p->v[i][X_IDX];
  7282. if( x<p->bbox[BBOX_X0_IDX] ) p->bbox[BBOX_X0_IDX] = x;
  7283. if( x>p->bbox[BBOX_X1_IDX] ) p->bbox[BBOX_X1_IDX] = x;
  7284. y = p->v[i][Y_IDX];
  7285. if( y>p->bbox[BBOX_Y1_IDX] ) p->bbox[BBOX_Y1_IDX] = y;
  7286. if( y<p->bbox[BBOX_Y0_IDX] ) p->bbox[BBOX_Y0_IDX] = y;
  7287. }
  7288. areacomp=(p->bbox[BBOX_X1_IDX] - p->bbox[BBOX_X0_IDX])*(p->bbox[BBOX_Y1_IDX]-p->bbox[BBOX_Y0_IDX])*1.00001;
  7289.  
  7290. p->center[X_IDX]=(p->bbox[BBOX_X1_IDX]-p->bbox[BBOX_X0_IDX])*0.5+p->bbox[BBOX_X0_IDX];
  7291. p->center[Y_IDX]=(p->bbox[BBOX_Y1_IDX]-p->bbox[BBOX_Y0_IDX])*0.5+p->bbox[BBOX_Y0_IDX];
  7292. if(area<=areacomp) {
  7293. return TCL_OK;
  7294. } else {
  7295. char errstr[256];
  7296. sprintf(errstr,"Area: %g Calculated: %g\n",area,areacomp);
  7297. Tcl_AppendResult(interp, "Area of polygon wonky ", errstr, 0);
  7298. return TCL_ERROR;
  7299. }
  7300. }
  7301. /* Odie_Poly_Compare */
  7302. int Odie_Poly_Compare(Odie_Polygon *polyA,Odie_Polygon *polyB){
  7303. int i,j,N;
  7304. if(!polyA || !polyB) {
  7305. return 0;
  7306. }
  7307. if(polyA->nVertex!=polyB->nVertex) {
  7308. return 0;
  7309. }
  7310. N=polyA->nVertex;
  7311. for(i=0;i<N;i++) {
  7312. if(VectorXY_SamePoint(polyA->v[i],polyB->v[0])) {
  7313. /* Check in either direction */
  7314. for(j=1;j<N;j++) {
  7315. if(
  7316. VectorXY_SamePoint(polyA->v[(i+j)%N],polyB->v[j])==0
  7317. &&
  7318. VectorXY_SamePoint(polyA->v[(i-j)%N],polyB->v[j])==0
  7319. ) {
  7320. return 0;
  7321. }
  7322. }
  7323. /* If we got here we pass */
  7324. return 1;
  7325. }
  7326. }
  7327. return 0;
  7328.  
  7329. }
  7330. /* *Odie_FaceXYZ_ToDict */
  7331. Tcl_Obj *Odie_FaceXYZ_ToDict(Odie_FaceXYZ *pPoly){
  7332. Tcl_Obj *element=Tcl_NewObj();
  7333. {
  7334. Tcl_Obj *value;
  7335. value=Tcl_NewIntObj(pPoly->id);
  7336. Odie_DictObjPut(NULL,element,"id",value);
  7337. }
  7338. {
  7339. Tcl_Obj *value;
  7340. value=Tcl_NewDoubleObj(pPoly->area);
  7341. Odie_DictObjPut(NULL,element,"area",value);
  7342. }
  7343. {
  7344. Tcl_Obj *value;
  7345.  
  7346. Odie_MatrixObj *C;
  7347. if(pPoly->is_2d) {
  7348. C=Odie_MatrixObj_Create(MATFORM_bbox_xy);
  7349. VectorXY_BBOX_Copy(C->matrix,pPoly->bbox_uv);
  7350. value=Matrix_To_TclObj(C);
  7351. } else {
  7352. C=Odie_MatrixObj_Create(MATFORM_aabb_xyz);
  7353. VectorXYZ_AABB_Copy(C->matrix,pPoly->bbox_xyz);
  7354. value=Matrix_To_TclObj(C);
  7355. }
  7356.  
  7357. Odie_DictObjPut(NULL,element,"bbox",value);
  7358. }
  7359. {
  7360. Tcl_Obj *value;
  7361. value=Tcl_NewIntObj(pPoly->bend);
  7362. Odie_DictObjPut(NULL,element,"bend",value);
  7363. }
  7364. {
  7365. Tcl_Obj *value;
  7366. value=VectorXYZ_To_TclObj(pPoly->center);
  7367. Odie_DictObjPut(NULL,element,"center",value);
  7368. }
  7369. {
  7370. Tcl_Obj *value;
  7371. value=Tcl_NewBooleanObj(pPoly->is_convex);
  7372. Odie_DictObjPut(NULL,element,"is_2d",value);
  7373. }
  7374. {
  7375. Tcl_Obj *value;
  7376. value=Tcl_NewBooleanObj(pPoly->is_convex);
  7377. Odie_DictObjPut(NULL,element,"is_convex",value);
  7378. }
  7379. {
  7380. Tcl_Obj *value;
  7381. value=VectorXYZ_To_TclObj(pPoly->normal);
  7382. Odie_DictObjPut(NULL,element,"normal",value);
  7383. }
  7384. {
  7385. Tcl_Obj *value;
  7386. value=Tcl_NewIntObj(pPoly->nVertex);
  7387. Odie_DictObjPut(NULL,element,"nVertex",value);
  7388. }
  7389. {
  7390. Tcl_Obj *value;
  7391. value=Tcl_NewDoubleObj(pPoly->radius);
  7392. Odie_DictObjPut(NULL,element,"radius",value);
  7393. }
  7394. {
  7395. Tcl_Obj *value;
  7396.  
  7397. Odie_MatrixObj *C;
  7398. C=Odie_MatrixObj_Create(MATFORM_affine);
  7399. Odie_Affine4x4_Copy(C->matrix,pPoly->rotation);
  7400. value=Matrix_To_TclObj(C);
  7401.  
  7402. Odie_DictObjPut(NULL,element,"rotation",value);
  7403. }
  7404. {
  7405. Tcl_Obj *value;
  7406.  
  7407. Odie_MatrixObj *C;
  7408. C=Odie_MatrixObj_Create(MATFORM_affine);
  7409. Odie_Affine4x4_Copy(C->matrix,pPoly->rotation_inv);
  7410. value=Matrix_To_TclObj(C);
  7411.  
  7412. Odie_DictObjPut(NULL,element,"rotation_inv",value);
  7413. }
  7414. return element;}
  7415. /* Odie_FaceXYZ_freeIntRepProc */
  7416. void Odie_FaceXYZ_freeIntRepProc(Tcl_Obj *objPtr){
  7417. Odie_Free(objPtr->internalRep.otherValuePtr);
  7418. objPtr->internalRep.otherValuePtr=NULL;
  7419. objPtr->typePtr=NULL;
  7420. }
  7421. /* Odie_FaceXYZ_dupIntRepProc */
  7422. void Odie_FaceXYZ_dupIntRepProc(Tcl_Obj *srcPtr,Tcl_Obj *dupPtr){
  7423. Odie_FaceXYZ *src=srcPtr->internalRep.otherValuePtr;
  7424. Odie_FaceXYZ *copy=Odie_FaceXYZ_Create(src->nVertex);
  7425. memcpy(copy,src,src->alloc_bytes);
  7426. Tcl_InvalidateStringRep(dupPtr);
  7427. dupPtr->typePtr=srcPtr->typePtr;
  7428. dupPtr->internalRep.otherValuePtr=copy;
  7429. }
  7430. /* Odie_FaceXYZ_updateStringProc */
  7431. void Odie_FaceXYZ_updateStringProc(Tcl_Obj *objPtr){
  7432. /* Update String Rep */
  7433. char outbuffer[256];
  7434. Tcl_DString result;
  7435. Odie_FaceXYZ *p=objPtr->internalRep.otherValuePtr;
  7436. int i,n;
  7437. Tcl_DStringInit(&result);
  7438. n=p->nVertex;
  7439.  
  7440. /* Express as 3d */
  7441. for(i=0; i<n; i++){
  7442. sprintf(outbuffer,"%g %g %g",(float)p->vertex_xyz[i][X_IDX],(float)p->vertex_xyz[i][Y_IDX],(float)p->vertex_xyz[i][Z_IDX]);
  7443. Tcl_DStringAppendElement(&result,outbuffer);
  7444. }
  7445.  
  7446. objPtr->length=Tcl_DStringLength(&result);
  7447. objPtr->bytes=Odie_Alloc(objPtr->length+1);
  7448. strcpy(objPtr->bytes,Tcl_DStringValue(&result));
  7449. Tcl_DStringFree(&result);
  7450. }
  7451. /* Odie_FaceXYZ_setFromAnyProc */
  7452. int Odie_FaceXYZ_setFromAnyProc(Tcl_Interp *interp,Tcl_Obj *objPtr){
  7453. /* Set internal rep from any Tcl_Obj */
  7454. if(objPtr->typePtr) {
  7455. if(objPtr->typePtr->setFromAnyProc==&Odie_FaceXYZ_setFromAnyProc && objPtr->internalRep.otherValuePtr) {
  7456. /*
  7457. ** Object is already of the type requested
  7458. */
  7459. return TCL_OK;
  7460. }
  7461. }
  7462. Odie_FaceXYZ *p;
  7463. int created=0;
  7464. if(Odie_FaceXYZ_GetFromTclObj(interp,objPtr,&p,&created)) {
  7465. return TCL_ERROR;
  7466. }
  7467. Tcl_InvalidateStringRep(objPtr);
  7468. objPtr->internalRep.otherValuePtr=p;
  7469. objPtr->typePtr=&odie_polygon_tclobjtype;
  7470. return TCL_OK;
  7471. }
  7472. /* *Odie_FaceXYZ_NewTclObj */
  7473. Tcl_Obj *Odie_FaceXYZ_NewTclObj(Odie_FaceXYZ *pPolygon){
  7474. Tcl_Obj *pResult;
  7475. pResult=Tcl_NewObj();
  7476. pResult->internalRep.otherValuePtr=pPolygon;
  7477. pResult->typePtr=&odie_polygon_tclobjtype;
  7478. Tcl_InvalidateStringRep(pResult);
  7479. Tcl_IncrRefCount(pResult);
  7480. return pResult;
  7481. }
  7482. /* *Odie_FaceXYZ_Create */
  7483. Odie_FaceXYZ *Odie_FaceXYZ_Create(int nVertex){
  7484. void *ptr;
  7485. Odie_FaceXYZ *p;
  7486. size_t size;
  7487. int maxVertex=nVertex+2; /* Allocate room for an additional 2 vertices */
  7488. if(nVertex<3) {
  7489. nVertex=3;
  7490. maxVertex=nVertex+2;
  7491. }
  7492. size=sizeof(*p)+maxVertex*sizeof(VectorXYZ)+maxVertex*sizeof(VectorXYZ);
  7493. ptr=Odie_Alloc(size);
  7494. p=(Odie_FaceXYZ *)ptr;
  7495. p->alloc_bytes=size;
  7496. p->maxVertex=maxVertex;
  7497. p->nVertex=nVertex;
  7498. p->vertex_uv=(ptr+sizeof(*p));
  7499. p->vertex_xyz=(ptr+sizeof(*p)+maxVertex*sizeof(VectorXYZ));
  7500. return p;
  7501. }
  7502. /* Odie_FaceXYZ_FromXYList */
  7503. int Odie_FaceXYZ_FromXYList(Tcl_Interp *interp,Tcl_Obj *objPtr,Odie_FaceXYZ **ptr){
  7504. int k,i,nVertex;
  7505. Tcl_Obj *pElem;
  7506. Odie_FaceXYZ *p;
  7507. if( Tcl_ListObjLength(interp, objPtr, &k) ) return TCL_ERROR;
  7508. /* Read in a series of doubles a X Y pairs */
  7509. if( k<6 ){
  7510. Tcl_AppendResult(interp, "need at least 3 vertices", 0);
  7511. return TCL_ERROR;
  7512. }
  7513. if( k&1 ){
  7514. Tcl_AppendResult(interp, "coordinates should come in pairs", 0);
  7515. return TCL_ERROR;
  7516. }
  7517. nVertex=k/2;
  7518. p=Odie_FaceXYZ_Create(nVertex);
  7519. for(i=0; i<nVertex; i++){
  7520. double d;
  7521. Tcl_ListObjIndex(0, objPtr, i*2, &pElem);
  7522. if(Tcl_GetDoubleFromObj(interp, pElem, &d)) goto createfail;
  7523. p->vertex_xyz[i][X_IDX] = d;
  7524.  
  7525. Tcl_ListObjIndex(0, objPtr, i*2+1, &pElem);
  7526. if(Tcl_GetDoubleFromObj(interp, pElem, &d)) goto createfail;
  7527. p->vertex_xyz[i][Y_IDX] = d;
  7528. p->vertex_xyz[i][Z_IDX] = 0.0;
  7529. }
  7530. if(Odie_FaceXYZ_Compute(interp,p)) goto createfail;
  7531. *ptr=p;
  7532. return TCL_OK;
  7533.  
  7534. createfail:
  7535. Odie_Free((char *)p);
  7536. return TCL_ERROR;
  7537. }
  7538. /* Odie_FaceXYZ_FromPoly */
  7539. int Odie_FaceXYZ_FromPoly(Tcl_Interp *interp,Tcl_Obj *objPtr,Odie_FaceXYZ **ptr){
  7540. int k,i,nVertex;
  7541. Tcl_Obj *pElem;
  7542. Odie_FaceXYZ *p;
  7543. Odie_Polygon *poly;
  7544. poly=objPtr->internalRep.otherValuePtr;
  7545. nVertex=poly->nVertex;
  7546. p=Odie_FaceXYZ_Create(nVertex);
  7547. for(i=0; i<nVertex; i++){
  7548. VectorXY_Copy(p->vertex_xyz[i],poly->v[i]);
  7549. p->vertex_xyz[i][Z_IDX] = 0.0;
  7550. }
  7551. if(Odie_FaceXYZ_Compute(interp,p)) goto createfail;
  7552. *ptr=p;
  7553. return TCL_OK;
  7554.  
  7555. createfail:
  7556. Odie_Free((char *)p);
  7557. return TCL_ERROR;
  7558. }
  7559. /* Odie_FaceXYZ_FromVectorList */
  7560. int Odie_FaceXYZ_FromVectorList(Tcl_Interp *interp,Tcl_Obj *objPtr,Odie_FaceXYZ **ptr){
  7561. int k,i,nVertex;
  7562. Tcl_Obj *pElem;
  7563. Odie_FaceXYZ *p;
  7564. if( Tcl_ListObjLength(interp, objPtr, &k) ) return TCL_ERROR;
  7565.  
  7566. if( k<3 ){
  7567. Tcl_AppendResult(interp, "need at least 3 vertices", 0);
  7568. return TCL_ERROR;
  7569. }
  7570. nVertex=k;
  7571. p=Odie_FaceXYZ_Create(nVertex);
  7572. for(i=0; i<p->nVertex; i++){
  7573. Tcl_ListObjIndex(0, objPtr, i, &pElem);
  7574. if(Odie_GetVectorXYZFromTclObj(interp,pElem,p->vertex_xyz[i])) goto createfail;
  7575. }
  7576. if(Odie_FaceXYZ_Compute(interp,p)) goto createfail;
  7577. *ptr=p;
  7578. return TCL_OK;
  7579.  
  7580. createfail:
  7581. Odie_Free((char *)p);
  7582. return TCL_ERROR;
  7583. }
  7584. /* Odie_ConvexPolygon_GetFromTclObj */
  7585. int Odie_ConvexPolygon_GetFromTclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,Odie_FaceXYZ **ptr,int *created){
  7586. int result;
  7587. result=Odie_FaceXYZ_GetFromTclObj(interp,objPtr,ptr,created);
  7588. if(result) {
  7589. return result;
  7590. }
  7591. Odie_FaceXYZ *pPoly=*ptr;
  7592. if(pPoly->is_convex) {
  7593. return TCL_OK;
  7594. }
  7595. if(interp) {
  7596. Tcl_AppendResult(interp,"Polygon is not convex",NULL);
  7597. }
  7598. if(*created) Odie_FaceXYZ_ShimmerOrFree_TclObj(objPtr,*ptr);
  7599. return TCL_ERROR;
  7600. }
  7601. /* Odie_FaceXYZ_GetFromTclObj */
  7602. int Odie_FaceXYZ_GetFromTclObj(Tcl_Interp *interp,Tcl_Obj *objPtr,Odie_FaceXYZ **ptr,int *created){
  7603. *created=1;
  7604. Tcl_Obj *pElem;
  7605. int k,first_element_length;
  7606.  
  7607. if(objPtr->typePtr) {
  7608. if(objPtr->typePtr->setFromAnyProc==&Odie_FaceXYZ_setFromAnyProc && objPtr->internalRep.otherValuePtr) {
  7609. /*
  7610. ** Object is already of the type requested
  7611. */
  7612. *ptr=objPtr->internalRep.otherValuePtr;
  7613. *created=0;
  7614. return TCL_OK;
  7615. }
  7616. if(objPtr->typePtr->setFromAnyProc==&PolygonObj_setFromAnyProc && objPtr->internalRep.otherValuePtr) {
  7617. /* Our first element is encoded as an ODIE vector */
  7618. *created=1;
  7619. return Odie_FaceXYZ_FromPoly(interp,objPtr,ptr);
  7620. }
  7621. }
  7622. *created=1;
  7623. if( Tcl_ListObjLength(interp, objPtr, &k) ) return TCL_ERROR;
  7624. if( k<3 ){
  7625. Tcl_AppendResult(interp, "need at least 3 vertices", 0);
  7626. return TCL_ERROR;
  7627. }
  7628. /* See if our first element is a valid XYZ Coordnate */
  7629. Tcl_ListObjIndex(0, objPtr, 0, &pElem);
  7630. if(pElem->typePtr) {
  7631. if(objPtr->typePtr->setFromAnyProc==&MatrixObj_setFromAnyProc && objPtr->internalRep.otherValuePtr) {
  7632. /* Our first element is encoded as an ODIE vector */
  7633. return Odie_FaceXYZ_FromVectorList(interp,objPtr,ptr);
  7634. }
  7635. }
  7636. /* Guess form by the list contents */
  7637. if( Tcl_ListObjLength(interp, pElem, &first_element_length) ) return TCL_ERROR;
  7638. if(first_element_length==1) {
  7639. /* The first element is only 1 element long, guess we have a stream of doubles */
  7640. return Odie_FaceXYZ_FromXYList(interp,objPtr,ptr);
  7641. }
  7642. if(first_element_length==2) {
  7643. /* The first element is 2 element long, guess we have a stream of vectors */
  7644. return Odie_FaceXYZ_FromVectorList(interp,objPtr,ptr);
  7645. }
  7646. if(first_element_length==3) {
  7647. /* The first element is 3 element long, guess we have a stream of vectors */
  7648. return Odie_FaceXYZ_FromVectorList(interp,objPtr,ptr);
  7649. }
  7650. /* Stop trying to quess */
  7651. Tcl_AppendResult(interp, "Cannot intepret input", 0);
  7652. return TCL_ERROR;
  7653. }
  7654. /* Odie_FaceXYZ_ShimmerOrFree_TclObj */
  7655. void Odie_FaceXYZ_ShimmerOrFree_TclObj(Tcl_Obj *objPtr,Odie_FaceXYZ *p){
  7656. if(objPtr->typePtr) {
  7657. if(objPtr->typePtr->setFromAnyProc==&Odie_FaceXYZ_setFromAnyProc) {
  7658. /*
  7659. ** Object is already of the type requested
  7660. */
  7661. return;
  7662. }
  7663. }
  7664. if(Tcl_IsShared(objPtr)) {
  7665. Odie_Free((char *)p);
  7666. return;
  7667. }
  7668. if(objPtr->typePtr && objPtr->typePtr->freeIntRepProc) {
  7669. Tcl_FreeInternalRepProc *freeIntRepProc=objPtr->typePtr->freeIntRepProc;
  7670. freeIntRepProc(objPtr);
  7671. }
  7672. objPtr->internalRep.otherValuePtr=p;
  7673. objPtr->typePtr=&odie_polygon_tclobjtype;
  7674. Tcl_IncrRefCount(objPtr);
  7675. return;
  7676. }
  7677. /* Odie_FaceXYZ_Compute */
  7678. int Odie_FaceXYZ_Compute(Tcl_Interp *interp,Odie_FaceXYZ *p){
  7679. double normal_length=0.0;
  7680. int i,j,k,rmax=0,r1;
  7681. double area=0.0;
  7682. double areacomp=0.0;
  7683. int is2d=1;
  7684. VectorXYZ SUM;
  7685. if(p->nVertex<3) {
  7686. if(interp) {
  7687. Tcl_AppendResult(interp,"Polygons need at least 3 vertices",NULL);
  7688. }
  7689. return TCL_ERROR;
  7690. }
  7691. while(VectorXYZ_SamePoint(p->vertex_xyz[p->nVertex-1],p->vertex_xyz[0])) {
  7692. p->nVertex--;
  7693. if(p->nVertex<=0) {
  7694. return TCL_ERROR;
  7695. }
  7696. }
  7697. VectorXYZ_Copy(p->vertex_xyz[p->nVertex],p->vertex_xyz[0]);
  7698. VectorXYZ_Zero(SUM);
  7699. VectorXYZ_Zero(p->normal);
  7700. VectorXYZ_Zero(p->center);
  7701. VectorXYZ_AABB_Reset(p->bbox_xyz);
  7702. for(i=0;i<p->nVertex;i++) {
  7703. VectorXYZ_AABB_Measure(p->vertex_xyz[i],p->bbox_xyz);
  7704. p->center[X_IDX]+=p->vertex_xyz[i][X_IDX];
  7705. p->center[Y_IDX]+=p->vertex_xyz[i][Y_IDX];
  7706. p->center[Y_IDX]+=p->vertex_xyz[i][Z_IDX];
  7707. }
  7708. p->center[X_IDX] /= p->nVertex;
  7709. p->center[Y_IDX] /= p->nVertex;
  7710. p->center[Z_IDX] /= p->nVertex;
  7711.  
  7712. if(fabs(p->bbox_xyz[Z_MAX_IDX])>__FLT_EPSILON__) {
  7713. is2d=0;
  7714. }
  7715. if(fabs(p->bbox_xyz[Z_MIN_IDX])>__FLT_EPSILON__) {
  7716. is2d=0;
  7717. }
  7718. p->is_2d=is2d;
  7719. if(is2d) {
  7720. p->normal[X_IDX]=0.0;
  7721. p->normal[Y_IDX]=0.0;
  7722. p->normal[Z_IDX]=1.0;
  7723. Odie_Affine4x4_Identity(p->rotation);
  7724. Odie_Affine4x4_Identity(p->rotation_inv);
  7725. for(i=0;i<=p->nVertex;i++) {
  7726. VectorXYZ_Copy(p->vertex_uv[i],p->vertex_xyz[i]);
  7727. }
  7728. } else {
  7729. for(i=0,j=1;i<p->nVertex;i++,j++) {
  7730. r1 = VectorXYZ_DistanceSq(p->center, p->vertex_xyz[i]);
  7731. if(r1>rmax) {
  7732. rmax=r1;
  7733. }
  7734. p->normal[X_IDX] += (p->vertex_xyz[j][Y_IDX]-p->vertex_xyz[i][Y_IDX]) * (p->vertex_xyz[j][Z_IDX]+p->vertex_xyz[i][Z_IDX]);
  7735. p->normal[Y_IDX] += (p->vertex_xyz[j][Z_IDX]-p->vertex_xyz[i][Z_IDX]) * (p->vertex_xyz[j][X_IDX]+p->vertex_xyz[i][X_IDX]);
  7736. p->normal[Z_IDX] += (p->vertex_xyz[j][X_IDX]-p->vertex_xyz[i][X_IDX]) * (p->vertex_xyz[j][Y_IDX]+p->vertex_xyz[i][Y_IDX]);
  7737. }
  7738. p->radius=sqrt(rmax);
  7739. normal_length=VectorXYZ_Magnitude(p->normal);
  7740. if(normal_length>0.0) {
  7741. double inv=1.0/normal_length;
  7742. p->normal[X_IDX]*=inv;
  7743. p->normal[Y_IDX]*=inv;
  7744. p->normal[Z_IDX]*=inv;
  7745. }
  7746. AFFINE rotation,translation;
  7747. Odie_Affine_From_Normal(rotation,p->normal);
  7748. Odie_Affine4x4_Translation(translation,p->center);
  7749. Odie_Affine4x4_Multiply(p->rotation_inv,rotation,translation);
  7750. Odie_Affine4x4_Inverse(p->rotation,p->rotation_inv);
  7751. /* Map the Polygon to UV Space */
  7752. for(i=0;i<=p->nVertex;i++) {
  7753. VectorXYZ_MatrixMultiply(p->vertex_uv[i],p->vertex_xyz[i],p->rotation);
  7754. }
  7755. }
  7756. VectorXYZ_Copy(p->vertex_uv[p->nVertex],p->vertex_xyz[0]);
  7757. /* Compute 2d information from the UV coordinates */
  7758. p->is_convex=1;
  7759. for(i=0; i<p->nVertex; i++){
  7760. int bend;
  7761. j=(i+1)%p->nVertex;
  7762. k=(i+2)%p->nVertex;
  7763. bend=VectorXY_BendDirection(p->vertex_uv[i], p->vertex_uv[j], p->vertex_uv[k]);
  7764. if(bend>0 && p->bend<0) {
  7765. p->is_convex=0;
  7766. } else if(bend<0 && p->bend>0) {
  7767. p->is_convex=0;
  7768. }
  7769. p->bend+=bend;
  7770. }
  7771. if(!p->is_convex) {
  7772. /*
  7773. ** A convex polygon is legal,
  7774. ** we just can't answer questions about area and intersections
  7775. */
  7776. return TCL_OK;
  7777. }
  7778. for(i=0; i<p->nVertex; i++){
  7779. area += 0.5*(p->vertex_uv[i][Y_IDX] + p->vertex_uv[i+1][Y_IDX])*(p->vertex_uv[i+1][X_IDX] - p->vertex_uv[i][X_IDX]);
  7780. }
  7781. if( area<0.0 ){
  7782. int b, e;
  7783. for(b=0, e=p->nVertex; b<e; b++, e--){
  7784. double t;
  7785. t = p->vertex_uv[b][X_IDX];
  7786. p->vertex_uv[b][X_IDX] = p->vertex_uv[e][X_IDX];
  7787. p->vertex_uv[e][X_IDX] = t;
  7788. t = p->vertex_uv[b][Y_IDX];
  7789. p->vertex_uv[b][Y_IDX] = p->vertex_uv[e][Y_IDX];
  7790. p->vertex_uv[e][Y_IDX] = t;
  7791. }
  7792. area = -area;
  7793. }
  7794. if(fabs(area)<__FLT_EPSILON__) {
  7795. area=0.0;
  7796. }
  7797. p->area = area;
  7798. p->bbox_uv[BBOX_X0_IDX] = p->bbox_uv[BBOX_X1_IDX] = p->vertex_uv[0][X_IDX];
  7799. p->bbox_uv[BBOX_Y1_IDX] = p->bbox_uv[BBOX_Y0_IDX] = p->vertex_uv[0][Y_IDX];
  7800. for(i=1; i<p->nVertex; i++){
  7801. double x, y;
  7802. x = p->vertex_uv[i][X_IDX];
  7803. if( x<p->bbox_uv[BBOX_X0_IDX] ) p->bbox_uv[BBOX_X0_IDX] = x;
  7804. if( x>p->bbox_uv[BBOX_X1_IDX] ) p->bbox_uv[BBOX_X1_IDX] = x;
  7805. y = p->vertex_uv[i][Y_IDX];
  7806. if( y>p->bbox_uv[BBOX_Y1_IDX] ) p->bbox_uv[BBOX_Y1_IDX] = y;
  7807. if( y<p->bbox_uv[BBOX_Y0_IDX] ) p->bbox_uv[BBOX_Y0_IDX] = y;
  7808. }
  7809. return TCL_OK;
  7810. }
  7811. /* *Odie_FaceXYZ_Simplify */
  7812. Odie_FaceXYZ *Odie_FaceXYZ_Simplify(Odie_FaceXYZ *pPolygonXYZ){
  7813. Odie_FaceXYZ *pNewPolygonXYZ;
  7814. int i,j,k,N;
  7815. pNewPolygonXYZ=Odie_FaceXYZ_Create(pPolygonXYZ->nVertex);
  7816. pNewPolygonXYZ->nVertex=0;
  7817. N=pPolygonXYZ->nVertex;
  7818.  
  7819. /* The first vertex always belongs */
  7820. VectorXYZ_Copy(pNewPolygonXYZ->vertex_xyz[0],pPolygonXYZ->vertex_xyz[0]);
  7821. pNewPolygonXYZ->nVertex++;
  7822. i=1;
  7823. j=(i-1) % N;
  7824. k=(i-2) % N;
  7825. while(i<N) {
  7826. /* Skip identical points */
  7827. while(VectorXYZ_SamePoint(pPolygonXYZ->vertex_xyz[i],pPolygonXYZ->vertex_xyz[j]) && i<N) {
  7828. i++;
  7829. }
  7830. /* Skip colinear points */
  7831. while(VectorXYZ_IsColinear(pPolygonXYZ->vertex_xyz[k],pPolygonXYZ->vertex_xyz[j],pPolygonXYZ->vertex_xyz[i]) && i<N) {
  7832. i++;
  7833. }
  7834. VectorXYZ_Copy(pNewPolygonXYZ->vertex_xyz[i],pPolygonXYZ->vertex_xyz[i]);
  7835. pNewPolygonXYZ->nVertex++;
  7836. k=j;
  7837. j=i;
  7838. i++;
  7839. }
  7840. return pNewPolygonXYZ;
  7841. }
  7842. /* Odie_FaceXYZ_Compare */
  7843. static inline int Odie_FaceXYZ_Compare(Odie_FaceXYZ *A,Odie_FaceXYZ *B){
  7844. Odie_FaceXYZ *pPolyA,*pPolyB;
  7845. int i,j=0,result=1;
  7846. if(!A || !B) return 0;
  7847. if(A==B) return 1;
  7848. pPolyA=Odie_FaceXYZ_Simplify(A);
  7849. pPolyB=Odie_FaceXYZ_Simplify(B);
  7850. if(pPolyA->nVertex!=pPolyB->nVertex) {
  7851. result=0; goto finished;
  7852. }
  7853. for(i=0;i<pPolyA->nVertex;i++) {
  7854. if(VectorXYZ_SamePoint(pPolyA->vertex_xyz[i],pPolyB->vertex_xyz[i])) continue;
  7855. /* Check the reverse */
  7856. j=pPolyA->nVertex-i-1;
  7857. if(!VectorXYZ_SamePoint(pPolyA->vertex_xyz[i],pPolyB->vertex_xyz[j])) {
  7858. result=0;
  7859. goto finished;
  7860. }
  7861. result=-1;
  7862. }
  7863. finished:
  7864. Odie_Free(pPolyA);
  7865. Odie_Free(pPolyB);
  7866. return result;
  7867. }
  7868. /* Odie_FaceXYZ_Coplaner */
  7869. static inline int Odie_FaceXYZ_Coplaner(Odie_FaceXYZ *A,Odie_FaceXYZ *B){
  7870. int i,j,ia=0,ja=0,ka=0;
  7871. if(!A || !B) return 0;
  7872. if(A==B) return 1;
  7873. for(i=0;i<A->nVertex;i++) {
  7874. int c;
  7875. ia=i;
  7876. ja=(i+1) % A->nVertex;
  7877. ka=(i+2) % A->nVertex;
  7878. for(j=0;j<B->nVertex;j++) {
  7879. c=VectorXYZ_IsCoplaner(A->vertex_xyz[ia],A->vertex_xyz[ja],A->vertex_xyz[ka],B->vertex_xyz[j]);
  7880. if(!c) {
  7881. return 0;
  7882. }
  7883. }
  7884. }
  7885. return 1;
  7886. }
  7887. /* PolygonUV_Within */
  7888. static inline int PolygonUV_Within(Odie_FaceXYZ *p, double x, double y){
  7889. /*
  7890. ** Return -1, 0, or 1 if the point x,y is outside, on, or within
  7891. ** the polygon p.
  7892. */
  7893. int res, i;
  7894. res = -1;
  7895. for(i=0; i<p->nVertex-1; i++){
  7896. double x0, y0, x1, y1, yP;
  7897. x0 = p->vertex_uv[i][X_IDX];
  7898. y0 = p->vertex_uv[i][Y_IDX];
  7899. x1 = p->vertex_uv[i+1][X_IDX];
  7900. y1 = p->vertex_uv[i+1][Y_IDX];
  7901. if( x0==x1 ){
  7902. if( x0==x && ((y0<=y && y1>=y) || (y1<=y && y0>=y)) ){
  7903. res = 0;
  7904. break;
  7905. }
  7906. continue;
  7907. }
  7908. if( x0>x1 ){
  7909. int t = x0;
  7910. x0 = x1;
  7911. x1 = t;
  7912. t = y0;
  7913. y0 = y1;
  7914. y1 = t;
  7915. }
  7916. if( x>=x1 || x<x0 ) continue;
  7917. yP = y1 - (x1-x)*(y1-y0)/(x1-x0);
  7918. if( yP == y ){ res = 0; break; }
  7919. if( yP > y ){ res = -res; }
  7920. }
  7921. return res;
  7922. }
  7923. /* Odie_FaceXYZ_Within */
  7924. static inline int Odie_FaceXYZ_Within(Odie_FaceXYZ *p, VectorXYZ POINT){
  7925. VectorXYZ a; /* Temporary variable to map coordinates during rotation */
  7926.  
  7927. /*
  7928. ** Return -1, 0, or 1 if the point x,y is outside, on, or within
  7929. ** the polygonxyz p.
  7930. */
  7931. if(!VectorXYZ_AABB_Within(POINT,p->bbox_xyz)) {
  7932. return -1;
  7933. }
  7934. /*
  7935. ** If we reach here it means that the closest point will be on the
  7936. ** permiter of the triangle. There are three line faces on the
  7937. ** permiter. Try them all.
  7938. */
  7939. int i, j;
  7940. for(i=0;i<p->nVertex;i++) {
  7941. j=(i+1)%p->nVertex;
  7942. if(VectorXYZ_PointIsOnSegment(POINT,p->vertex_xyz[i], p->vertex_xyz[j])) {
  7943. return 0;
  7944. }
  7945. }
  7946. /*
  7947. ** Translate the coordinate to the same rotation as the polygon
  7948. ** and use 2d checks
  7949. */
  7950. VectorXYZ_MatrixMultiply(a,POINT,p->rotation);
  7951. return PolygonUV_Within(p,a[X_IDX],a[Y_IDX]);
  7952. }
  7953. /* Odie_FaceXYZ_IntersectTest */
  7954. static int Odie_FaceXYZ_IntersectTest(Odie_FaceXYZ *p1,Odie_FaceXYZ *p2){
  7955. double area,x,y;
  7956. area = Odie_FaceXYZ_AreaOfIntersection(p1,p2,&x,&y);
  7957. if(area>0) {
  7958. return 1;
  7959. } else {
  7960. return 0;
  7961. }
  7962. }
  7963. /* Odie_FaceXYZ_AreaOfIntersection */
  7964. static double Odie_FaceXYZ_AreaOfIntersection(Odie_FaceXYZ *p1,Odie_FaceXYZ *p2,double *xin,double *yin){
  7965. double area=0;
  7966. double xInside = 0.0, yInside = 0.0;
  7967. double x0, y0, x1, y1, dx, dy, xP, yP, xC, yC;
  7968. int i, j, cnt;
  7969. int score, bestScore;
  7970. static const int n = 50;
  7971. char hit[50][50];
  7972.  
  7973. /* Compute the overlap of the bounding boxes of the two polygons. */
  7974. x0 = p1->bbox_uv[BBOX_X0_IDX] < p2->bbox_uv[BBOX_X0_IDX] ? p2->bbox_uv[BBOX_X0_IDX] : p1->bbox_uv[BBOX_X0_IDX];
  7975. y0 = p1->bbox_uv[BBOX_Y1_IDX] > p2->bbox_uv[BBOX_Y1_IDX] ? p2->bbox_uv[BBOX_Y1_IDX] : p1->bbox_uv[BBOX_Y1_IDX];
  7976. x1 = p1->bbox_uv[BBOX_X1_IDX] > p2->bbox_uv[BBOX_X1_IDX] ? p2->bbox_uv[BBOX_X1_IDX] : p1->bbox_uv[BBOX_X1_IDX];
  7977. y1 = p1->bbox_uv[BBOX_Y0_IDX] < p2->bbox_uv[BBOX_Y0_IDX] ? p2->bbox_uv[BBOX_Y0_IDX] : p1->bbox_uv[BBOX_Y0_IDX];
  7978.  
  7979. /* Divide the intersection of the bounding boxes into a n-by-n grid
  7980. ** and count the number of elements in this grid whose centers fall
  7981. ** within both polygons. This will be our approximation for the
  7982. ** intersection of the polygons themselves.
  7983. */
  7984. dx = (x1-x0)/n;
  7985. dy = (y1-y0)/n;
  7986. cnt = 0;
  7987. xC = yC = 0.0;
  7988. for(i=0; i<n; i++){
  7989. xP = x0 + dx*(i+0.5);
  7990. for(j=0; j<n; j++){
  7991. yP = y0 + dy*(j+0.5);
  7992. if( PolygonUV_Within(p1, xP, yP)>0 && PolygonUV_Within(p2, xP, yP)>0 ){
  7993. cnt++;
  7994. hit[i][j] = 1;
  7995. xC += xP;
  7996. yC += yP;
  7997. }else{
  7998. hit[i][j] = 0;
  7999. }
  8000. }
  8001. }
  8002.  
  8003. /* We need to find a good approximation for the center of the
  8004. ** overlap. Begin by computing the center of mass for the
  8005. ** overlapping region. Then find the point inside the intersection
  8006. ** that is nearest the center of mass.
  8007. */
  8008. if( cnt>0 ){
  8009. area = cnt*(x1-x0)*(y0-y1)/(n*n);
  8010. xC /= cnt;
  8011. yC /= cnt;
  8012. bestScore = -1.0;
  8013. for(i=0; i<n; i++){
  8014. xP = x0 + dx*(i+0.5);
  8015. for(j=0; j<n; j++){
  8016. if( !hit[i][j] ) continue;
  8017. yP = y0 + dy*(j+0.5);
  8018. score = dist(xP,yP,xC,yC);
  8019. if( score<bestScore || bestScore<0.0 ){
  8020. xInside = xP;
  8021. yInside = yP;
  8022. bestScore = score;
  8023. }
  8024. }
  8025. }
  8026. } else {
  8027. area=0.0;
  8028. }
  8029. *xin=xInside;
  8030. *yin=yInside;
  8031. return area;
  8032. }
  8033. /* SegmentSet_Delete */
  8034. static void SegmentSet_Delete(ClientData clientData){
  8035. SegmentSet *pSet=(SegmentSet *)clientData;
  8036. SegmentSetClear(pSet);
  8037. Odie_Free(pSet);
  8038. }
  8039. /* SegmentSet_Clone */
  8040. static int SegmentSet_Clone(
  8041. Tcl_Interp* interp, /* Tcl interpreter for error reporting */
  8042. ClientData metadata, /* Metadata to be cloned */
  8043. ClientData* newMetaData /* Where to put the cloned metadata */
  8044. ){
  8045. SegmentSet *src=(SegmentSet*)metadata;
  8046. SegmentSet *dest=(SegmentSet*)Odie_Alloc(sizeof(SegmentSet));
  8047. SegmentSetCopy(dest,src);
  8048. *newMetaData=(ClientData*)dest;
  8049. return TCL_OK;
  8050. }
  8051. /* *Segment_To_Dict */
  8052. Tcl_Obj *Segment_To_Dict(Segment *pSeg){
  8053. Tcl_Obj *element=Tcl_NewObj();
  8054. {
  8055. Tcl_Obj *value;
  8056. value=Tcl_NewIntObj(pSeg->id);
  8057. Odie_DictObjPut(NULL,element,"id:",value);
  8058. }
  8059. {
  8060. Tcl_Obj *value;
  8061. value=Tcl_NewBooleanObj(pSeg->isVirtual);
  8062. Odie_DictObjPut(NULL,element,"virtual:",value);
  8063. }
  8064. {
  8065. Tcl_Obj *value;
  8066. value=VectorXYZ_To_TclObj(pSeg->from);
  8067. Odie_DictObjPut(NULL,element,"from:",value);
  8068. }
  8069. {
  8070. Tcl_Obj *value;
  8071. value=VectorXYZ_To_TclObj(pSeg->to);
  8072. Odie_DictObjPut(NULL,element,"to:",value);
  8073. }
  8074. {
  8075. Tcl_Obj *value;
  8076. value=Tcl_NewBooleanObj(pSeg->isVirtual);
  8077. Odie_DictObjPut(NULL,element,"exported:",value);
  8078. }
  8079. {
  8080. Tcl_Obj *value;
  8081. value=Tcl_NewIntObj(pSeg->idLC);
  8082. Odie_DictObjPut(NULL,element,"id_left:",value);
  8083. }
  8084. {
  8085. Tcl_Obj *value;
  8086. value=Tcl_NewIntObj(pSeg->idRC);
  8087. Odie_DictObjPut(NULL,element,"id_right:",value);
  8088. }
  8089. {
  8090. Tcl_Obj *value;
  8091. value=Tcl_NewBooleanObj(pSeg->isVirtual);
  8092. Odie_DictObjPut(NULL,element,"ignore:",value);
  8093. }
  8094. {
  8095. Tcl_Obj *value;
  8096.  
  8097. if(pSeg->boundfwd) {
  8098. value=Tcl_NewIntObj(pSeg->boundfwd->faceid);
  8099. } else {
  8100. value=Tcl_NewIntObj(0);
  8101. }
  8102.  
  8103. Odie_DictObjPut(NULL,element,"facefwd:",value);
  8104. }
  8105. {
  8106. Tcl_Obj *value;
  8107.  
  8108. if(pSeg->boundback) {
  8109. value=Tcl_NewIntObj(pSeg->boundback->faceid);
  8110. } else {
  8111. value=Tcl_NewIntObj(0);
  8112. }
  8113.  
  8114. Odie_DictObjPut(NULL,element,"faceback:",value);
  8115. }
  8116. return element;}
  8117. /* *SegmentSet_Insert_XYZ */
  8118. Segment *SegmentSet_Insert_XYZ(SegmentSet *pSet,int id,VectorXYZ A,VectorXYZ B){
  8119. Segment *pSeg;
  8120. if(id>0) {
  8121. if(SegmentSet_FindById(pSet, id)) return NULL;
  8122. }
  8123. VectorXYZ_GridAlign(A,pSet->grid);
  8124. VectorXYZ_GridAlign(B,pSet->grid);
  8125. if(VectorXYZ_SamePoint(A,B)) return NULL;
  8126. SegmentSet_AddVertex(pSet,A);
  8127. SegmentSet_AddVertex(pSet,B);
  8128. pSeg=Segment_FindByLocation(pSet,A,B);
  8129. if(pSeg) return pSeg;
  8130. pSeg=Segment_Create(pSet,id);
  8131. if(pSeg) {
  8132. Segment_SetToFrom(pSet,pSeg,A,B);
  8133. }
  8134. return pSeg;
  8135. }
  8136. /* SegmentSet_Cleanup_Coincident */
  8137. static int SegmentSet_Cleanup_Coincident(SegmentSet *pSet,Segment *pAB){
  8138. Link *qLoop,*qNext;
  8139. int changes=0;
  8140. for(qLoop=pSet->pAll; qLoop; qLoop=qNext){
  8141. int c;
  8142. Segment *pCD;
  8143. pCD = qLoop->pLinkNode;
  8144. qNext = qLoop->pNext;
  8145. VectorXYZ ICEPT;
  8146.  
  8147. VectorXYZ_ClosestPointOnSegment(pAB->from,pAB->to,pCD->from,ICEPT);
  8148. VectorXYZ_GridAlign(ICEPT,pSet->grid);
  8149. if(VectorXYZ_SamePoint(ICEPT,pCD->from)) {
  8150. changes+=SegmentSet_AddVertex(pSet,ICEPT);
  8151. }
  8152. VectorXYZ_ClosestPointOnSegment(pAB->from,pAB->to,pCD->to,ICEPT);
  8153. VectorXYZ_GridAlign(ICEPT,pSet->grid);
  8154. if(VectorXYZ_SamePoint(ICEPT,pCD->to)) {
  8155. changes+=SegmentSet_AddVertex(pSet,ICEPT);
  8156. }
  8157. }
  8158. for(qLoop=pSet->pAll; qLoop; qLoop=qNext){
  8159. int c;
  8160. Segment *pCD;
  8161. pCD = qLoop->pLinkNode;
  8162. qNext = qLoop->pNext;
  8163. VectorXYZ ICEPT1,ICEPT2;
  8164. /* Evaluate lower to higher */
  8165. if(pCD->id == pAB->id) continue;
  8166. c=VectorXYZ_LineLineCoincident(pAB->from,pAB->to,pCD->from,pCD->to,ICEPT1,ICEPT2);
  8167. if(c<=0) continue;
  8168. changes+=SegmentSet_AddVertex(pSet,ICEPT1);
  8169. if(!VectorXYZ_SamePoint(ICEPT1,ICEPT2)) {
  8170. changes+=SegmentSet_AddVertex(pSet,ICEPT2);
  8171. }
  8172. }
  8173. return changes;
  8174. }
  8175. /* Segset_Insert_Polygon */
  8176. int Segset_Insert_Polygon(SegmentSet *pSet,Odie_FaceXYZ *p,int comptid){
  8177. int h,i,j,reversed=0;
  8178. int bend=0;
  8179. if(p->nVertex<3) {
  8180. return TCL_ERROR;
  8181. }
  8182. for(i=0;i<=p->nVertex;i++) {
  8183. VectorXYZ h_uv,i_uv,j_uv;
  8184. j=(i+1)%p->nVertex;
  8185. h=(i-1)%p->nVertex;
  8186. VectorXYZ_MatrixMultiply(h_uv,p->vertex_xyz[h],pSet->rotation);
  8187. VectorXYZ_MatrixMultiply(i_uv,p->vertex_xyz[i],pSet->rotation);
  8188. VectorXYZ_MatrixMultiply(j_uv,p->vertex_xyz[j],pSet->rotation);
  8189. bend+=VectorXY_BendDirection(h_uv, i_uv, j_uv);
  8190. }
  8191. for(i=0;i<=p->nVertex;i++) {
  8192. Segment *pSeg;
  8193. j=(i+1)%p->nVertex;
  8194. h=(i-1)%p->nVertex;
  8195. pSeg=SegmentSet_Insert_XYZ(pSet,-1,p->vertex_xyz[i],p->vertex_xyz[j]);
  8196. if(pSeg) {
  8197. if(VectorXYZ_SamePoint(pSeg->from,p->vertex_xyz[j])) {
  8198. reversed=1;
  8199. }
  8200. pSeg->isVirtual=0;
  8201. /*
  8202. ** Paint the inside edge of the polygon with the comptid
  8203. */
  8204. if(reversed) {
  8205. /* The line inserted into the segment set was backward from what we specified */
  8206. if(bend<=0) {
  8207. /* The polygon was given in a counter clockwise direction */
  8208. pSeg->idRC=comptid;
  8209. } else {
  8210. pSeg->idLC=comptid;
  8211. }
  8212. } else {
  8213. if(bend<=0) {
  8214. /* The polygon was given in a counter clockwise direction */
  8215. pSeg->idRC=comptid;
  8216. } else {
  8217. pSeg->idLC=comptid;
  8218. }
  8219. }
  8220. }
  8221. }
  8222. return TCL_OK;
  8223. }
  8224. /* SegmentSetCopy */
  8225. void SegmentSetCopy(SegmentSet *dest,SegmentSet *src){
  8226. SegmentSetClear(dest);
  8227. memset(dest, 0, sizeof(SegmentSet));
  8228. Link *pLoop, *pNext;
  8229. for(pLoop=src->pAll; pLoop; pLoop=pNext){
  8230. Segment *pAB,*pNewSeg;
  8231. pAB = pLoop->pLinkNode;
  8232. pNext = pLoop->pNext;
  8233. pNewSeg=SegmentSet_Insert_XYZ(dest,pAB->id,pAB->from,pAB->to);
  8234. if(pNewSeg) {
  8235. Segment_Imprint(pAB,pNewSeg);
  8236. }
  8237. }
  8238. }
  8239. /* Segment_OnList */
  8240. static int Segment_OnList(Segment *pSeg, Link *pList){
  8241. while( pList ){
  8242. if( pList->pLinkNode==pSeg ) return 1;
  8243. pList = pList->pNext;
  8244. }
  8245. return 0;
  8246. }
  8247. /* *SegmentSet_FindById */
  8248. static Segment *SegmentSet_FindById(SegmentSet *p, int id){
  8249. int h;
  8250. Link *pLink;
  8251.  
  8252. h = hashInt(id);
  8253. for(pLink = p->hashId[h]; pLink; pLink=pLink->pNext){
  8254. Segment *pSeg=pLink->pLinkNode;
  8255. if( pSeg->id==id ) return pSeg;
  8256. }
  8257. return 0;
  8258. }
  8259. /* *Segment_FindByLocation */
  8260. Segment *Segment_FindByLocation(SegmentSet *pSet, VectorXYZ A, VectorXYZ B){
  8261. /*
  8262. ** Find and return the line segment that goes from A to B. Return NULL
  8263. ** if there is not such line segment
  8264. */
  8265. Link *pX;
  8266. Segment *p;
  8267. int h;
  8268. VectorXYZ_GridAlign(A,pSet->grid);
  8269. h = hashVectorXYZ(A);
  8270. for(pX=pSet->hashFrom[h]; pX; pX=pX->pNext){
  8271. p = pX->pLinkNode;
  8272. if( VectorXYZ_SamePoint(p->from, A) && VectorXYZ_SamePoint(p->to, B) ){
  8273. return p;
  8274. }
  8275. if( VectorXYZ_SamePoint(p->to, A) && VectorXYZ_SamePoint(p->from, B) ){
  8276. return p;
  8277. }
  8278. }
  8279. for(pX=pSet->hashTo[h]; pX; pX=pX->pNext){
  8280. p = pX->pLinkNode;
  8281. if( VectorXYZ_SamePoint(p->from, A) && VectorXYZ_SamePoint(p->to, B) ){
  8282. return p;
  8283. }
  8284. if( VectorXYZ_SamePoint(p->to, A) && VectorXYZ_SamePoint(p->from, B) ){
  8285. return p;
  8286. }
  8287. }
  8288. return 0;
  8289. }
  8290. /* Segment_Imprint */
  8291. static void Segment_Imprint(Segment *pSrc,Segment *pDest){
  8292. if(pSrc==pDest) return;
  8293. pDest->isVirtual=pSrc->isVirtual;
  8294. pDest->idLC=pSrc->idLC;
  8295. pDest->idRC=pSrc->idRC;
  8296. }
  8297. /* Segment_SetToFrom */
  8298. static void Segment_SetToFrom(SegmentSet *pSet, Segment *p, VECTORXYZ from, VECTORXYZ to){
  8299. int h;
  8300. VectorXYZ_GridAlign(from,pSet->grid);
  8301. VectorXYZ_GridAlign(to,pSet->grid);
  8302. if(VectorXYZ_SamePoint(from,p->from) && VectorXYZ_SamePoint(to,p->to)) {
  8303. return;
  8304. }
  8305. LinkRemove(&p->pFrom);
  8306. LinkRemove(&p->pTo);
  8307. pSet->modified=1;
  8308. VectorXYZ_Copy(p->from,from);
  8309. VectorXYZ_Copy(p->to,to);
  8310. VectorXY_BBOX_Measure(p->from,pSet->bbox_uv);
  8311. VectorXY_BBOX_Measure(p->to,pSet->bbox_uv);
  8312. h = hashVectorXYZ(p->from);
  8313. LinkInsert(&pSet->hashFrom[h], &p->pFrom);
  8314. h = hashVectorXYZ(p->to);
  8315. LinkInsert(&pSet->hashTo[h], &p->pTo);
  8316. }
  8317. /* *Segment_Create */
  8318. static inline Segment *Segment_Create(SegmentSet *pSet,int newid){
  8319. Link *pLoop,*pNext;
  8320. Segment *p=NULL;
  8321. int id,h;
  8322. for(pLoop=pSet->pFree; pLoop; pLoop=pNext){
  8323. p=pLoop->pLinkNode;
  8324. pNext=pLoop->pNext;
  8325. if(p) {
  8326. LinkRemove(&p->pFree);
  8327. id=p->id;
  8328. memset(p,0,sizeof(*p));
  8329. if(newid<=0) {
  8330. p->id=id;
  8331. } else if(p->id>pSet->nextid) {
  8332. pSet->nextid=p->id;
  8333. }
  8334. break;
  8335. }
  8336. }
  8337. if(!p) {
  8338. p=(Segment *)Odie_Alloc( sizeof(*p) );
  8339. if(newid<=0) {
  8340. pSet->nextid++;
  8341. p->id=pSet->nextid;
  8342. } else if(p->id>pSet->nextid) {
  8343. pSet->nextid=p->id;
  8344. }
  8345. }
  8346. if(!p) {
  8347. return NULL;
  8348. }
  8349. LinkInit(p->pAll, p);
  8350. LinkInit(p->pSet, p);
  8351. LinkInit(p->pHash, p);
  8352. LinkInit(p->pFrom, p);
  8353. LinkInit(p->pTo, p);
  8354.  
  8355. LinkInit(p->pFree, p);
  8356. LinkInsert(&pSet->pAll, &p->pAll);
  8357. h = hashInt(p->id);
  8358. LinkInsert(&pSet->hashId[h], &p->pHash);
  8359. pSet->modified=1;
  8360. pSet->nSeg++;
  8361. pSet->pCurrent = p;
  8362. return p;
  8363. }
  8364. /* SegmentSetRemove */
  8365. static inline void SegmentSetRemove(SegmentSet *pSet, Segment *p){
  8366. /*
  8367. ** Remove a segment from the segment set
  8368. */
  8369. pSet->modified=1;
  8370. LinkRemove(&p->pAll);
  8371. /* We intentionally do not remove pSeg->pSet because it might not be
  8372. ** a well-formed list */
  8373. LinkRemove(&p->pHash);
  8374. LinkRemove(&p->pFrom);
  8375. LinkRemove(&p->pTo);
  8376.  
  8377. LinkInit(p->pAll, p);
  8378. //LinkInit(p->pSet, p);
  8379. LinkInit(p->pHash, p);
  8380. LinkInit(p->pFrom, p);
  8381. LinkInit(p->pTo, p);
  8382. LinkInsert(&pSet->pFree,&p->pFree);
  8383. pSet->nSeg--;
  8384. if( pSet->pCurrent==p ){
  8385. pSet->pCurrent = pSet->pAll ? pSet->pAll->pLinkNode : 0;
  8386. }
  8387. }
  8388. /* SegRelink */
  8389. static inline void SegRelink(SegmentSet *pSet, Segment *p){
  8390. /*
  8391. ** Call this routine to relink into a segment when the
  8392. ** Seg.from vector changes.
  8393. */
  8394. int h;
  8395. pSet->modified=1;
  8396. LinkRemove(&p->pHash);
  8397. LinkRemove(&p->pFrom);
  8398. LinkRemove(&p->pTo);
  8399. LinkRemove(&p->pFree);
  8400. h = hashInt(p->id);
  8401. LinkInsert(&pSet->hashId[h], &p->pHash);
  8402. h = hashVectorXY(p->from);
  8403. LinkInsert(&pSet->hashFrom[h], &p->pFrom);
  8404. h = hashVectorXY(p->to);
  8405. LinkInsert(&pSet->hashTo[h], &p->pTo);
  8406. }
  8407. /* SegmentSetClear */
  8408. static inline void SegmentSetClear(SegmentSet *pSet){
  8409. /*
  8410. ** Remove all segments from a segment set
  8411. */
  8412. Link *pLoop,*pNext;
  8413. Segment *p;
  8414. SegmentSet_ClearFaceEdgeCache(pSet);
  8415. while( pSet->pAll ){
  8416. assert( pSet->nSeg>0 );
  8417. p=pSet->pAll->pLinkNode;
  8418. SegmentSetRemove(pSet, p);
  8419. }
  8420. for(pLoop=pSet->pFree; pLoop; pLoop=pNext){
  8421. p=pLoop->pLinkNode;
  8422. pNext=pLoop->pNext;
  8423. LinkRemove(&p->pFree);
  8424. Odie_Free((char *)p);
  8425. }
  8426. assert( pSet->nSeg==0 );
  8427. }
  8428. /* SegmentSetStep */
  8429. static inline void SegmentSetStep(SegmentSet *pSet){
  8430. /*
  8431. ** Advance the pSet->pAll pointer so that it is pointing to a different
  8432. ** segment.
  8433. */
  8434. if( pSet->pCurrent ){
  8435. Link *pNext = pSet->pCurrent->pAll.pNext;
  8436. pSet->pCurrent = pNext ? pNext->pLinkNode : 0;
  8437. }
  8438. if( pSet->pCurrent==0 ){
  8439. pSet->pCurrent = pSet->pAll ? pSet->pAll->pLinkNode : 0;
  8440. }
  8441. }
  8442. /* SegmentSet_AddVertex */
  8443. static int SegmentSet_AddVertex(SegmentSet *pSet,VectorXYZ A){
  8444. Link *pLoop,*pNext;
  8445. VectorXYZ B,ICEPT;
  8446. int changes=0;
  8447. VectorXYZ_GridAlign(A,pSet->grid);
  8448. for(pLoop=pSet->pAll; pLoop; pLoop=pNext){
  8449. int delete=0;
  8450. Segment *pAB,*pNew;
  8451. Segment *found;
  8452. pAB = pLoop->pLinkNode;
  8453. pNext=pLoop->pNext;
  8454. if(VectorXYZ_SamePoint(A,pAB->from)) continue;
  8455. if(VectorXYZ_SamePoint(A,pAB->to)) continue;
  8456. VectorXYZ_ClosestPointOnSegment(pAB->from,pAB->to,A,ICEPT);
  8457. if(!VectorXYZ_SamePoint(ICEPT,A)) continue;
  8458. changes++;
  8459. /* Preserve the segment's original destination */
  8460. VectorXYZ_Copy(B,pAB->to);
  8461. found=Segment_FindByLocation(pSet,pAB->from,A);
  8462. if(!found) {
  8463. /* Truncate the first part of the segment */
  8464. Segment_SetToFrom(pSet,pAB,pAB->from,A);
  8465. } else {
  8466. delete=1;
  8467. }
  8468. found=Segment_FindByLocation(pSet,A,B);
  8469. if(!found) {
  8470. if(delete) {
  8471. /*
  8472. ** A segment exists for the first part of this segment
  8473. ** but not the second. Rather than throw this link out
  8474. ** just to re-create it, recycle
  8475. */
  8476. delete=0;
  8477. Segment_SetToFrom(pSet,pAB,A,B);
  8478. } else {
  8479. pNew=SegmentSet_Insert_XYZ(pSet,-1,A,B);
  8480. if(pNew) {
  8481. Segment_Imprint(pAB,pNew);
  8482. }
  8483. }
  8484. }
  8485. if(delete) {
  8486. /* A segment already exists, delete this one */
  8487. SegmentSetRemove(pSet,pAB);
  8488. }
  8489. }
  8490. return changes;
  8491. }
  8492. /* SegmentSet_Cleanup */
  8493. int SegmentSet_Cleanup(SegmentSet *pSet,int looseend){
  8494. Link *pLoop,*pNext;
  8495. Link *qLoop,*qNext;
  8496. Segment *pAB,*pCD;
  8497. int count=0;
  8498. int loop=0;
  8499. int match=0;
  8500. for(pLoop=pSet->pAll; pLoop; pLoop=pNext){
  8501. pAB = pLoop->pLinkNode;
  8502. pNext = pLoop->pNext;
  8503. pAB->test=0;
  8504. }
  8505. /* Cleanup loose ends */
  8506. for(pLoop=pSet->pAll; pLoop; pLoop=pNext){
  8507. VectorXYZ A,B;
  8508. Link *pList;
  8509. int nSeg;
  8510. pAB = pLoop->pLinkNode;
  8511. pNext = pLoop->pNext;
  8512. VectorXYZ_Copy(A,pAB->from);
  8513. VectorXYZ_Copy(B,pAB->to);
  8514. VectorXYZ_GridAlign(A,pSet->grid);
  8515. VectorXYZ_GridAlign(B,pSet->grid);
  8516. Segment_SetToFrom(pSet,pAB,A,B);
  8517. }
  8518. for(pLoop=pSet->pAll; pLoop; pLoop=pNext){
  8519. pAB = pLoop->pLinkNode;
  8520. pNext = pLoop->pNext;
  8521. count+=SegmentSet_Cleanup_Coincident(pSet,pAB);
  8522. }
  8523.  
  8524. if(looseend) {
  8525. for(pLoop=pSet->pAll; pLoop; pLoop=pNext){
  8526. Link *pList;
  8527. int nSeg;
  8528. pAB = pLoop->pLinkNode;
  8529. pNext = pLoop->pNext;
  8530. pList = SegmentSet_Segments_AtVertex(pSet, pAB->from,&nSeg);
  8531. if( nSeg < 2 ){
  8532. pAB->test=1;
  8533. match++;
  8534. }
  8535. pList = SegmentSet_Segments_AtVertex(pSet, pAB->to,&nSeg);
  8536. if( nSeg < 2 ){
  8537. pAB->test=1;
  8538. match++;
  8539. }
  8540. }
  8541. /* Cleanup overlapping walls */
  8542. for(pLoop=pSet->pAll; pLoop; pLoop=pNext){
  8543. pAB = pLoop->pLinkNode;
  8544. pNext = pLoop->pNext;
  8545. if(pAB->test) continue;
  8546. if(VectorXYZ_DistanceSq(pAB->from,pAB->to)<pSet->gridSq) {
  8547. pAB->test=1;
  8548. continue;
  8549. }
  8550. for(qLoop=pNext; qLoop; qLoop=qNext){
  8551. pCD = qLoop->pLinkNode;
  8552. qNext = qLoop->pNext;
  8553. if(pCD->test) continue;
  8554. if(VectorXYZ_SamePoint(pAB->from,pCD->from)) {
  8555. if(VectorXYZ_SamePoint(pAB->to,pCD->to)) {
  8556. if(pAB->isVirtual>pCD->isVirtual) {
  8557. pAB->test=1;
  8558. } else if(pAB->id>pCD->id) {
  8559. pAB->test=1;
  8560. } else {
  8561. pCD->test=1;
  8562. }
  8563. continue;
  8564. }
  8565. }
  8566. if(VectorXYZ_SamePoint(pAB->from,pCD->from)) {
  8567. if(VectorXYZ_SamePoint(pAB->to,pCD->to)) {
  8568. if(pAB->isVirtual>pCD->isVirtual) {
  8569. pAB->test=1;
  8570. } else if(pAB->id>pCD->id) {
  8571. pAB->test=1;
  8572. } else {
  8573. pCD->test=1;
  8574. }
  8575. }
  8576. }
  8577. }
  8578. }
  8579. for(pLoop=pSet->pAll; pLoop; pLoop=pNext){
  8580. pAB = pLoop->pLinkNode;
  8581. pNext = pLoop->pNext;
  8582. if(pAB->test) {
  8583. SegmentSetRemove(pSet,pAB);
  8584. count++;
  8585. }
  8586. }
  8587. }
  8588. return count;
  8589. }
  8590. /* SegmentSet_Interference_Check */
  8591. static int SegmentSet_Interference_Check(SegmentSet *pSet,VectorXYZ A,VectorXYZ B){
  8592. Link *qLoop,*qNext;
  8593. int onsegment=0;
  8594. for(qLoop=pSet->pAll; qLoop; qLoop=qNext){
  8595. int c;
  8596. Segment *pTest;
  8597. VectorXYZ ICEPT1,ICEPT2;
  8598. qNext = qLoop->pNext;
  8599. pTest = qLoop->pLinkNode;
  8600. if((VectorXYZ_DistanceSq(A,pTest->from) < pSet->gridSq) && (VectorXYZ_DistanceSq(B,pTest->to) < pSet->gridSq)) return 3;
  8601. if((VectorXYZ_DistanceSq(A,pTest->to) < pSet->gridSq) && (VectorXYZ_DistanceSq(B,pTest->from) < pSet->gridSq)) return 3;
  8602. if(VectorXYZ_PointIsOnSegment(A,pTest->from,pTest->to)) {
  8603. onsegment++;
  8604. continue;
  8605. }
  8606. c=VectorXYZ_LineLineCoincident(A,B,pTest->from,pTest->to,ICEPT1,ICEPT2);
  8607. if(c>0) {
  8608. return c;
  8609. }
  8610. }
  8611. /* If the ray did not touch any segment return a unique error code */
  8612. if(onsegment==0) {
  8613. return 16;
  8614. }
  8615. return 0;
  8616. }
  8617. /* SegmentSet_Edge_Connection */
  8618. static int SegmentSet_Edge_Connection(SegmentSet *pSet,VectorXYZ A,int comptid,VectorXYZ RESULT){
  8619. Link *pLoop,*pNext;
  8620. Segment *pAB,*pBest=NULL;
  8621. VectorXYZ ICEPT;
  8622. double pBestDist=HUGE_VAL;
  8623. for(pLoop=pSet->pAll; pLoop; pLoop=pNext){
  8624. double score;
  8625. int interference;
  8626. pAB = pLoop->pLinkNode;
  8627. pNext = pLoop->pNext;
  8628. if(comptid!=0 && pAB->idRC!=comptid && pAB->idLC!=comptid) {
  8629. continue;
  8630. }
  8631. VectorXYZ_ClosestPointOnSegment(pAB->from,pAB->to,A,ICEPT);
  8632. VectorXYZ_GridAlign(ICEPT,pSet->grid);
  8633. score=VectorXYZ_DistanceSq(A,ICEPT);
  8634. if(score<pSet->gridSq) continue;
  8635. interference=SegmentSet_Interference_Check(pSet,A,ICEPT);
  8636. if(interference>0) continue;
  8637. if(!pBest || score<pBestDist) {
  8638. pBest=pAB;
  8639. pBestDist=score;
  8640. VectorXYZ_Copy(RESULT,ICEPT);
  8641. }
  8642. }
  8643. if(pBest) {
  8644. return TCL_OK;
  8645. }
  8646. return TCL_ERROR;
  8647. }
  8648. /* Segment_Compute_UV */
  8649. inline extern void Segment_Compute_UV(SegmentSet *pSet,Segment *pSeg,VectorXYZ uvfrom,VectorXYZ uvto){
  8650. VectorXYZ_MatrixMultiply(uvfrom,pSeg->from,pSet->rotation);
  8651. VectorXYZ_MatrixMultiply(uvto,pSeg->to,pSet->rotation);
  8652. }
  8653. /* SegmentSet_Convex_Connection */
  8654. static int SegmentSet_Convex_Connection(SegmentSet *pSet,Segment *pAB,int back,VectorXYZ RESULT){
  8655. Link *pLoop;
  8656. Segment *pCD,*pBest=NULL;
  8657. VectorXYZ A,B,AB,C,ICEPT,A_UV,B_UV,C_UV;
  8658. double pBestAngle=4*M_PI;
  8659. double pBestDist=HUGE_VAL;
  8660. double angle,rangle,len;
  8661. double rightangle=M_PI*0.5;
  8662. int ortho=0,i;
  8663.  
  8664. /* Try to ray cast the vector and find an intercept continuing along the line */
  8665. if(back) {
  8666. VectorXYZ_Copy(A,pAB->to);
  8667. VectorXYZ_Copy(B,pAB->from);
  8668. } else {
  8669. VectorXYZ_Copy(A,pAB->from);
  8670. VectorXYZ_Copy(B,pAB->to);
  8671. }
  8672. VectorXYZ_MatrixMultiply(A_UV,A,pSet->rotation);
  8673. VectorXYZ_MatrixMultiply(B_UV,B,pSet->rotation);
  8674. VectorXYZ_Subtract(AB,A_UV,B_UV);
  8675. len=pSet->grid;
  8676. angle=atan2(AB[Y_IDX],AB[X_IDX]);
  8677. for(i=-1;i<1;i++) {
  8678. rangle=angle+(M_PI*0.5*i);
  8679. rangle-=fmod(rangle,M_PI*0.5);
  8680. C_UV[X_IDX]=A_UV[X_IDX]+cos(rangle)*len;
  8681. C_UV[Y_IDX]=A_UV[Y_IDX]+sin(rangle)*len;
  8682. C_UV[Z_IDX]=A_UV[Z_IDX];
  8683. VectorXYZ_MatrixMultiply(C,C_UV,pSet->rotation_inv);
  8684. for(pLoop=pSet->pAll; pLoop; pLoop=pLoop->pNext){
  8685. double x,y;
  8686. int c;
  8687. VectorXYZ ICEPT1,ICEPT2;
  8688. pCD = pLoop->pLinkNode;
  8689. if(pCD->ignore) continue;
  8690. if(pCD==pAB) continue;
  8691. if(VectorXYZ_SamePoint(pAB->from,pCD->from)) continue;
  8692. if(VectorXYZ_SamePoint(pAB->from,pCD->to)) continue;
  8693. if(VectorXYZ_SamePoint(pAB->to,pCD->from)) continue;
  8694. if(VectorXYZ_SamePoint(pAB->to,pCD->to)) continue;
  8695. c=VectorXYZ_LineLineIntersect(A,C,pCD->from,pCD->to,ICEPT1,ICEPT2,&x,&y);
  8696. if(c>0) {
  8697. int interference;
  8698. double score;
  8699. if(!VectorXYZ_PointIsOnSegment(ICEPT1,pCD->from,pCD->to)) {
  8700. interference=16;
  8701. } else {
  8702. interference=SegmentSet_Interference_Check(pSet,A,ICEPT1);
  8703. }
  8704. if(interference<=0) {
  8705. if(fabs(angle-rangle)<pBestAngle) {
  8706. score=VectorXYZ_Distance(A,ICEPT1);
  8707. if(score>(pSet->grid*10) && (!pBest || score<pBestDist)) {
  8708. pBest=pCD;
  8709. pBestDist=score;
  8710. VectorXYZ_Copy(RESULT,ICEPT1);
  8711. pBestAngle=rangle;
  8712. }
  8713. }
  8714. }
  8715. if(!VectorXYZ_PointIsOnSegment(ICEPT2,pCD->from,pCD->to)) {
  8716. interference=16;
  8717. } else {
  8718. interference=SegmentSet_Interference_Check(pSet,A,ICEPT2);
  8719. }
  8720. if(interference<=0) {
  8721. if(fabs(angle-rangle)<pBestAngle) {
  8722. score=VectorXYZ_DistanceSq(A,ICEPT2);
  8723. if(score>(pSet->grid*10) && (!pBest || score<pBestDist)) {
  8724. pBest=pCD;
  8725. pBestDist=score;
  8726. VectorXYZ_Copy(RESULT,ICEPT2);
  8727. pBestAngle=rangle;
  8728. }
  8729. }
  8730. }
  8731. }
  8732. }
  8733. }
  8734. if(pBest) {
  8735. return TCL_OK;
  8736. }
  8737. return TCL_ERROR;
  8738. }
  8739. /* SegmentSetNextBend */
  8740. static int SegmentSetNextBend(
  8741. SegmentSet *pSet,
  8742. Segment *pAB,
  8743. int backwards,
  8744. Segment **ppSeg, /* OUT: First segment clockwise from xR,yR->xV,yV */
  8745. int *pfBack, /* OUT: True if output segment goes backwards */
  8746. int *pfBend, /* OUT: Bend direction */
  8747. double *pfAngle
  8748. ){
  8749. Segment *pSegThis;
  8750. int thisBack,thisBend;
  8751. double thisAngle;
  8752. pSegThis=pAB;
  8753. thisBack=backwards;
  8754. thisBend=0;
  8755. while(thisBend==0) {
  8756. if(SegmentSetNext(pSet, pSegThis, thisBack,ppSeg,pfBack,pfBend,pfAngle)) {
  8757. return TCL_ERROR;
  8758. }
  8759. thisBack=*pfBack;
  8760. thisBend=*pfBend;
  8761. if(thisBend==0) {
  8762. pSegThis->isBoundary=1;
  8763. }
  8764. pSegThis=*ppSeg;
  8765. }
  8766. return TCL_OK;
  8767. }
  8768. /* SegmentSet_SelfCheck */
  8769. static int SegmentSet_SelfCheck(Tcl_Interp *interp, SegmentSet *p){
  8770. Link *pLink;
  8771. Segment *pSeg;
  8772. int h;
  8773. char zErr[200];
  8774.  
  8775. for(pLink=p->pAll; pLink; pLink=pLink->pNext){
  8776. pSeg = pLink->pLinkNode;
  8777. h = hashInt(pSeg->id);
  8778. if(!Segment_OnList(pSeg, p->hashId[h]) ){
  8779. sprintf(zErr, "segment %d missing from hashId[%d]", pSeg->id, h);
  8780. Tcl_SetResult(interp, zErr, TCL_VOLATILE);
  8781. return TCL_ERROR;
  8782. }
  8783. h = hashCoord(pSeg->from[X_IDX], pSeg->from[Y_IDX]);
  8784. if(!Segment_OnList(pSeg, p->hashFrom[h]) ){
  8785. sprintf(zErr, "segment %d missing from hashFrom[%d]", pSeg->id, h);
  8786. Tcl_SetResult(interp, zErr, TCL_VOLATILE);
  8787. return TCL_ERROR;
  8788. }
  8789. h = hashCoord(pSeg->to[X_IDX], pSeg->to[Y_IDX]);
  8790. if(!Segment_OnList(pSeg, p->hashTo[h]) ){
  8791. sprintf(zErr, "segment %d missing from hashTo[%d]", pSeg->id, h);
  8792. Tcl_SetResult(interp, zErr, TCL_VOLATILE);
  8793. return TCL_ERROR;
  8794. }
  8795. }
  8796. return TCL_OK;
  8797. }
  8798. /* *SegmentSet_Segments_AtVertex */
  8799. static Link *SegmentSet_Segments_AtVertex(SegmentSet *p, VectorXYZ point,int *nSeg){
  8800. Link *pList = 0;
  8801. Link *pI;
  8802. int h,count=0;
  8803. VectorXYZ_GridAlign(point,p->grid);
  8804. h = hashVectorXYZ(point);
  8805. for(pI=p->hashFrom[h]; pI; pI=pI->pNext){
  8806. Segment *pSeg = pI->pLinkNode;
  8807. if( pSeg->ignore_fwd ) continue;
  8808. if(VectorXYZ_SamePoint(point,pSeg->from)) {
  8809. //assert( !segmentOnList(pSeg, pList) );
  8810. count++;
  8811. LinkInit(pSeg->pSet, pSeg);
  8812. LinkInsert(&pList, &pSeg->pSet);
  8813. }
  8814. }
  8815. for(pI=p->hashTo[h]; pI; pI=pI->pNext){
  8816. Segment *pSeg = pI->pLinkNode;
  8817. if( pSeg->ignore_back ) continue;
  8818. if(VectorXYZ_SamePoint(point,pSeg->to)) {
  8819. //assert( !segmentOnList(pSeg, pList) );
  8820. count++;
  8821. LinkInit(pSeg->pSet, pSeg);
  8822. LinkInsert(&pList, &pSeg->pSet);
  8823. }
  8824. }
  8825. *nSeg=count;
  8826. return pList;
  8827. }
  8828. /* SegmentSetNext */
  8829. static int SegmentSetNext(
  8830. SegmentSet *pSet,
  8831. Segment *pAB,
  8832. int backwards,
  8833. Segment **ppSeg, /* OUT: First segment clockwise from xR,yR->xV,yV */
  8834. int *pfBack, /* OUT: True if output segment goes backwards */
  8835. int *pfBend, /* OUT: Bend direction */
  8836. double *pfAngle
  8837. ){
  8838. VectorXYZ remote,vertex,remote_uv,vertex_uv;
  8839. Link *pI,*vList;
  8840. int i,best=-1;
  8841. int nSeg=0;
  8842. struct {
  8843. Segment *pSeg;
  8844. int isBack;
  8845. double angle;
  8846. int bend;
  8847. int edge;
  8848. VectorXYZ uv_remote;
  8849. } *aSeg, aSegStatic[20];
  8850.  
  8851. /*
  8852. pAB->ignore_fwd=1;
  8853. pAB->ignore_back=1;
  8854. */
  8855. if(backwards) {
  8856. VectorXYZ_Copy(remote,pAB->to);
  8857. VectorXYZ_Copy(vertex,pAB->from);
  8858. } else {
  8859. VectorXYZ_Copy(remote,pAB->from);
  8860. VectorXYZ_Copy(vertex,pAB->to);
  8861. }
  8862. VectorXYZ_MatrixMultiply(remote_uv,remote,pSet->rotation);
  8863. VectorXYZ_MatrixMultiply(vertex_uv,vertex,pSet->rotation);
  8864. vList=SegmentSet_Segments_AtVertex(pSet,vertex,&nSeg);
  8865. if(nSeg==0) {
  8866. *ppSeg=NULL;
  8867. *pfBack=0;
  8868. *pfBend=2;
  8869. *pfAngle=2*M_PI;
  8870. return TCL_ERROR;
  8871. }
  8872. if( nSeg<=sizeof(aSegStatic)/sizeof(aSegStatic[0]) ){
  8873. aSeg = aSegStatic;
  8874. }else{
  8875. aSeg = (void *)Odie_Alloc( nSeg*sizeof(*aSeg) );
  8876. }
  8877. for(pI=vList, i=0; pI; i++, pI=pI->pNext){
  8878. Segment *pSeg;
  8879. aSeg[i].pSeg = pSeg = pI->pLinkNode;
  8880. if( VectorXYZ_SamePoint(pSeg->from,vertex)) {
  8881. aSeg[i].isBack = 0;
  8882. aSeg[i].edge=pSeg->isVirtual||(pSeg->idRC>0);
  8883. VectorXYZ_MatrixMultiply(aSeg[i].uv_remote,pSeg->to,pSet->rotation);
  8884. } else {
  8885. aSeg[i].isBack = 1;
  8886. aSeg[i].edge=pSeg->isVirtual||(pSeg->idLC>0);
  8887. VectorXYZ_MatrixMultiply(aSeg[i].uv_remote,pSeg->from,pSet->rotation);
  8888. }
  8889. if(VectorXYZ_SamePoint(aSeg[i].uv_remote,remote)) {
  8890. aSeg[i].angle = 2*M_PI;
  8891. aSeg[i].bend = -2;
  8892. } else {
  8893. aSeg[i].angle = VectorXY_Angle_Three_Point(remote_uv, vertex_uv, aSeg[i].uv_remote);
  8894. aSeg[i].bend = VectorXY_BendDirection(remote_uv, vertex_uv, aSeg[i].uv_remote);
  8895. }
  8896. }
  8897. best=0;
  8898. for(i=1;i<nSeg;i++) {
  8899. if(aSeg[i].angle<aSeg[best].angle) {
  8900. best=i;
  8901. }
  8902. }
  8903. *ppSeg=aSeg[best].pSeg;
  8904. *pfBack=aSeg[best].isBack;
  8905. *pfBend=aSeg[best].bend;
  8906. *pfAngle=aSeg[best].angle;
  8907. if( aSeg!=aSegStatic ){
  8908. Tcl_Free((char *) aSeg );
  8909. }
  8910. return TCL_OK;
  8911. }
  8912. /* SegmentSet_ClearFaceEdgeCache */
  8913. static void SegmentSet_ClearFaceEdgeCache(SegmentSet *pSet){
  8914. if(!pSet->aBoundary) return;
  8915. Odie_Free(pSet->aBoundary);
  8916. pSet->aBoundary=NULL;
  8917. pSet->modified=0;
  8918. }
  8919. /* FaceBoundary_Mark_Degenerate */
  8920. static void FaceBoundary_Mark_Degenerate(FaceBoundary *pFace,int code){
  8921. FaceBoundary *qFace,*pFaceNext;
  8922. for(qFace=pFace;qFace;qFace=pFaceNext) {
  8923. pFaceNext=qFace->pNext;
  8924. qFace->pNext=NULL;
  8925. qFace->isloop=0;
  8926. qFace->faceid=qFace->id;
  8927. }
  8928. pFace->faceid=pFace->id;
  8929. pFace->nSeg=1;
  8930. pFace->isloop=code;
  8931. pFace->pNext=NULL;
  8932. }
  8933. /* SegmentSet_BuildFaceEdgeCache_ExpandRight */
  8934. static int SegmentSet_BuildFaceEdgeCache_ExpandRight(SegmentSet *pSet,int faceid,int stage){
  8935. FaceBoundary *sFace;
  8936. FaceBoundary *pFace;
  8937. FaceBoundary *oFace=NULL;
  8938. Link *pLoop;
  8939. VectorXYZ start;
  8940. Segment *pSeg,*pAB,*pBC;
  8941. int pbcback,pbcbend,idx;
  8942. double pbcangle;
  8943.  
  8944. sFace=pFace=&pSet->aBoundary[faceid];
  8945. /*
  8946. ** If this boundary is part of a loop, or the end of a loop continue
  8947. */
  8948. if(sFace->pNext || sFace->isloop>0) {
  8949. return 0;
  8950. }
  8951. /*
  8952. ** Don't expand the backface of real walls until stage 2
  8953. */
  8954. if(stage<1 && !sFace->pSeg->isVirtual) {
  8955. if(sFace->outside_edge) return 0;
  8956. }
  8957.  
  8958. /*
  8959. ** Detect degenerate loops if they wrap back to a different point
  8960. ** than our starting point. Reset the flag we use to detect that.
  8961. */
  8962. for(idx=0;idx<(pSet->nSeg*2);idx++) {
  8963. pSet->aBoundary[idx].parsed=0;
  8964. pSet->aBoundary[idx].pSeg->ignore=0;
  8965. pSet->aBoundary[idx].pSeg->ignore_fwd=0;
  8966. pSet->aBoundary[idx].pSeg->ignore_back=0;
  8967. pSet->aBoundary[idx].angle=0;
  8968. }
  8969. sFace->nSeg=1;
  8970. sFace->facebend=0;
  8971.  
  8972. pSeg=pAB=sFace->pSeg;
  8973. if(pFace->backwards) {
  8974. VectorXYZ_Copy(start,pSeg->to);
  8975. } else {
  8976. VectorXYZ_Copy(start,pSeg->from);
  8977. }
  8978. while(pAB) {
  8979. int atstart=0;
  8980. if(SegmentSetNext(pSet,pAB,pFace->backwards,&pBC,&pbcback,&pbcbend,&pbcangle)) {
  8981. /*
  8982. ** If this case occurs, we reached the end of the line without
  8983. ** returning to the start. Mark this section as degenerate
  8984. */
  8985. FaceBoundary_Mark_Degenerate(sFace,3);
  8986. return 1;
  8987. }
  8988. if(!pBC) {
  8989. FaceBoundary_Mark_Degenerate(sFace,4);
  8990. return 1;
  8991. }
  8992. /*
  8993. ** If we have returned to the start mark the beginning and end
  8994. ** of the loop
  8995. */
  8996. if(pbcback) {
  8997. oFace=pBC->boundback;
  8998. atstart=VectorXYZ_SamePoint(start,pBC->to);
  8999. } else {
  9000. oFace=pBC->boundfwd;
  9001. atstart=VectorXYZ_SamePoint(start,pBC->from);
  9002. }
  9003. if(oFace==sFace || atstart) {
  9004. sFace->isloop=1;
  9005. sFace->nSeg++;
  9006. if(sFace->nSeg<3) {
  9007. FaceBoundary_Mark_Degenerate(sFace,0);
  9008. } else {
  9009. pFace->faceid=faceid;
  9010. pFace->pNext=oFace;
  9011. pFace->isloop=2;
  9012. }
  9013. return 1;
  9014. }
  9015. if(oFace->parsed) {
  9016. /*
  9017. ** This loop has encountered a knot
  9018. */
  9019. FaceBoundary_Mark_Degenerate(sFace,0);
  9020. return 1;
  9021. }
  9022. if(oFace->faceid!=oFace->id) {
  9023. /*
  9024. ** This loop has bumped up against a different loop
  9025. ** Try to find another vertex
  9026. */
  9027. if(stage<2) {
  9028. FaceBoundary_Mark_Degenerate(sFace,0);
  9029. return 1;
  9030. } else {
  9031. if(oFace->backwards) {
  9032. oFace->pSeg->ignore_back=1;
  9033. } else {
  9034. oFace->pSeg->ignore_fwd=1;
  9035. }
  9036. continue;
  9037. }
  9038. }
  9039. if(VectorXYZ_SamePoint(pAB->from,pBC->to)) {
  9040. if(VectorXYZ_SamePoint(pBC->from,pAB->to)) {
  9041. if(oFace->backwards) {
  9042. oFace->pSeg->ignore_back=1;
  9043. } else {
  9044. oFace->pSeg->ignore_fwd=1;
  9045. }
  9046. continue;
  9047. }
  9048. }
  9049. sFace->facebend+=pbcbend;
  9050. oFace->parsed=1;
  9051.  
  9052. /*
  9053. ** Add this segment to the end of the list and
  9054. ** mark the segment as part of the same face
  9055. */
  9056. pFace->faceid=faceid;
  9057. pFace->pNext=oFace;
  9058. oFace->faceid=faceid;
  9059. oFace->bend=pbcbend;
  9060. oFace->angle=pbcangle;
  9061. sFace->nSeg++;
  9062. pAB=pBC;
  9063. pFace=oFace;
  9064. }
  9065. return 1;
  9066. }
  9067. /* SegmentSet_BuildFaceEdgeCache */
  9068. static void SegmentSet_BuildFaceEdgeCache(SegmentSet *pSet){
  9069. Link *pLoop;
  9070. int nBound=0;
  9071. int i,changes=0,count=0;
  9072. size_t asize;
  9073. if(pSet->modified) {
  9074. SegmentSet_ClearFaceEdgeCache(pSet);
  9075. SegmentSet_Cleanup(pSet,0);
  9076. } else {
  9077. /* Return immediately if the cache already exists */
  9078. if(pSet->aBoundary) {
  9079. return;
  9080. }
  9081. }
  9082. nBound=(pSet->nSeg*2);
  9083. asize=sizeof(FaceBoundary)*nBound;
  9084. pSet->aBoundary=(FaceBoundary *)Odie_Alloc(asize);
  9085. i=nBound=0;
  9086. for(pLoop=pSet->pAll; pLoop; pLoop=pLoop->pNext){
  9087. Segment *pSeg=pLoop->pLinkNode;
  9088. if(!pSeg->idRC && !pSeg->idLC) {
  9089. pSeg->isVirtual=1;
  9090. }
  9091. pSeg->ignore_fwd=0;
  9092. pSeg->ignore_back=0;
  9093.  
  9094.  
  9095. pSeg->boundfwd=&pSet->aBoundary[i];
  9096. pSet->aBoundary[i].id=i;
  9097. pSet->aBoundary[i].pSeg=pSeg;
  9098. pSet->aBoundary[i].nSeg=0;
  9099. pSet->aBoundary[i].backwards=0;
  9100. pSet->aBoundary[i].isloop=0;
  9101. pSet->aBoundary[i].facebend=0;
  9102. pSet->aBoundary[i].pNext=NULL;
  9103. pSet->aBoundary[i].bend=2;
  9104. if(pSeg->idLC<0) {
  9105. pSet->aBoundary[i].inside_edge=0;
  9106. pSet->aBoundary[i].outside_edge=1;
  9107. } else {
  9108. if(pSeg->idLC>0) {
  9109. pSet->aBoundary[i].inside_edge=1;
  9110. pSet->aBoundary[i].outside_edge=0;
  9111. } else if(pSeg->idRC>0) {
  9112. pSet->aBoundary[i].inside_edge=0;
  9113. pSet->aBoundary[i].outside_edge=1;
  9114. }
  9115. }
  9116. i++;
  9117. pSeg->boundback=&pSet->aBoundary[i];
  9118. pSet->aBoundary[i].id=i;
  9119. pSet->aBoundary[i].pSeg=pSeg;
  9120. pSet->aBoundary[i].nSeg=0;
  9121. pSet->aBoundary[i].backwards=1;
  9122. pSet->aBoundary[i].isloop=0;
  9123. pSet->aBoundary[i].facebend=0;
  9124. pSet->aBoundary[i].pNext=NULL;
  9125. pSet->aBoundary[i].bend=2;
  9126. if(pSeg->idRC<0) {
  9127. pSet->aBoundary[i].inside_edge=0;
  9128. pSet->aBoundary[i].outside_edge=1;
  9129. } else {
  9130. if(pSeg->idRC>0) {
  9131. pSet->aBoundary[i].inside_edge=1;
  9132. pSet->aBoundary[i].outside_edge=0;
  9133. } else if(pSeg->idLC>0) {
  9134. pSet->aBoundary[i].inside_edge=0;
  9135. pSet->aBoundary[i].outside_edge=1;
  9136. }
  9137. }
  9138. i++;
  9139. }
  9140.  
  9141. nBound=i;
  9142. /* Incubation stage. Let the clear cut winners take shape */
  9143. changes=0;
  9144. /* On the first pass ignore backfaces for "real" panels */
  9145. for(count=0;count<nBound;count++) {
  9146. if(count>0 && changes==0) {
  9147. break;
  9148. }
  9149. changes=0;
  9150. for(i=0;i<nBound;i++) {
  9151. changes+=SegmentSet_BuildFaceEdgeCache_ExpandRight(pSet,i,0);
  9152. }
  9153. }
  9154. /* On the second pass include backfaces for real panels */
  9155. for(count=0;count<nBound;count++) {
  9156. if(count>0 && changes==0) {
  9157. break;
  9158. }
  9159. changes=0;
  9160. for(i=0;i<nBound;i++) {
  9161. changes+=SegmentSet_BuildFaceEdgeCache_ExpandRight(pSet,i,1);
  9162. }
  9163. }
  9164. /* On the second pass include backfaces for real panels */
  9165. for(count=0;count<nBound;count++) {
  9166. if(count>0 && changes==0) {
  9167. break;
  9168. }
  9169. changes=0;
  9170. for(i=0;i<nBound;i++) {
  9171. changes+=SegmentSet_BuildFaceEdgeCache_ExpandRight(pSet,i,2);
  9172. }
  9173. }
  9174. }
  9175. /*
  9176. ** This widget translates 3-D coordinates onto a flat canvas by splitting
  9177. ** the 3-D space into layers and stacking the layers on the canvas.
  9178. **
  9179. ** The layers are decks of the ship. The highest layer (or deck) is drawn
  9180. ** at the top of the page. The next layer down is drawn below the top layer.
  9181. ** and so forth down the canvas. In other words, the 3D object is drawn
  9182. ** by showing a set of 2D slices where each slice is viewed from above.
  9183. **
  9184. ** The original 3D coordinates are called "actual" coordinates. When
  9185. ** translated into the 2D canvas they are called "canvas" coordinates.
  9186. **
  9187. ** The actual coordinate system is right-handed. The X axis increases to
  9188. ** the right. The Y axis increases going up. The Z axis comes out of the
  9189. ** page at the viewer. The canvas coordinate system is left-handed. The
  9190. ** X axis increase to the right but the Y axis increases going down.
  9191. **
  9192. ** A plotter is a object with methods. The details of the available
  9193. ** methods and what each does are described in comments before the
  9194. ** implementation of each method.
  9195. */
  9196. /* Plotter_Delete */
  9197. static void Plotter_Delete(ClientData clientData){
  9198. /*
  9199. ** This routine is called when a plotter is deleted. All the memory and
  9200. ** other resources allocated by this plotter is recovered.
  9201. */
  9202. Plotter *p = (Plotter*)clientData;
  9203. Odie_Free((char *)p);
  9204. }
  9205. /* Plotter_Clone */
  9206. static int Plotter_Clone(
  9207. Tcl_Interp* interp, /* Tcl interpreter for error reporting */
  9208. ClientData metadata, /* Metadata to be cloned */
  9209. ClientData* newMetaData /* Where to put the cloned metadata */
  9210. ){
  9211. Tcl_SetObjResult(interp,
  9212. Tcl_NewStringObj("PLOTTERs are not clonable", -1));
  9213. /* For now... */
  9214. return TCL_ERROR;
  9215. }
  9216. /* Plotter_xCanvasToActual */
  9217. static inline double Plotter_xCanvasToActual(Plotter *p,double cx){
  9218. return (cx+p->rXOffset)*p->rZoom;
  9219. }
  9220. /* Plotter_yCanvasToActual */
  9221. static inline double Plotter_yCanvasToActual(Plotter *p,double cy){
  9222. return -1.0*(cy+p->rYOffset)*p->rZoom;
  9223. }
  9224. /* Plotter_xActualToCanvas */
  9225. static inline double Plotter_xActualToCanvas(Plotter *p,double ax){
  9226. /*
  9227. ** Convert a Y coordinate from actual to canvas coordinates for a
  9228. ** given deck.
  9229. */
  9230. return (ax/p->rZoom)-p->rXOffset;
  9231. }
  9232. /* Plotter_yActualToCanvas */
  9233. static inline double Plotter_yActualToCanvas(Plotter *p,double ay){
  9234. /*
  9235. ** Convert a Y coordinate from actual to canvas coordinates for a
  9236. ** given deck.
  9237. */
  9238. return -1.0*(ay/p->rZoom)-p->rYOffset;
  9239. }
  9240. /*
  9241. ** This widget translates 3-D coordinates onto a flat canvas by splitting
  9242. ** the 3-D space into layers and stacking the layers on the canvas.
  9243. **
  9244. ** The layers are decks of the ship. The highest layer (or deck) is drawn
  9245. ** at the top of the page. The next layer down is drawn below the top layer.
  9246. ** and so forth down the canvas. In other words, the 3D object is drawn
  9247. ** by showing a set of 2D slices where each slice is viewed from above.
  9248. **
  9249. ** The original 3D coordinates are called "actual" coordinates. When
  9250. ** translated into the 2D canvas they are called "canvas" coordinates.
  9251. **
  9252. ** The actual coordinate system is right-handed. The X axis increases to
  9253. ** the right. The Y axis increases going up. The Z axis comes out of the
  9254. ** page at the viewer. The canvas coordinate system is left-handed. The
  9255. ** X axis increase to the right but the Y axis increases going down.
  9256. **
  9257. ** A slicer is a object with methods. The details of the available
  9258. ** methods and what each does are described in comments before the
  9259. ** implementation of each method.
  9260. */
  9261. /* Slicer_Delete */
  9262. static void Slicer_Delete(ClientData clientData){
  9263. /*
  9264. ** This routine is called when a slicer is deleted. All the memory and
  9265. ** other resources allocated by this slicer is recovered.
  9266. */
  9267. Slicer *p = (Slicer*)clientData;
  9268. int i;
  9269. for(i=0; i<p->nSlice; i++){
  9270. Odie_Free((char *)p->a[i].zName);
  9271. Odie_Free((char *)p->a[i].xz);
  9272. }
  9273. Odie_Free((char *)p->a);
  9274. Odie_Free((char *)p);
  9275. }
  9276. /* Slicer_Clone */
  9277. static int Slicer_Clone(
  9278. Tcl_Interp* interp, /* Tcl interpreter for error reporting */
  9279. ClientData metadata, /* Metadata to be cloned */
  9280. ClientData* newMetaData /* Where to put the cloned metadata */
  9281. ){
  9282. Tcl_SetObjResult(interp,
  9283. Tcl_NewStringObj("SLICERs are not clonable", -1));
  9284. /* For now... */
  9285. return TCL_ERROR;
  9286. }
  9287. /* Slicer_xCanvasToActual */
  9288. static double Slicer_xCanvasToActual(Slicer *p,struct OneSlice *pS, double cx){
  9289. double ax;
  9290. if(p->nSlice==1) {
  9291. ax = cx*p->rZoom;
  9292. } else {
  9293. ax = cx*p->rZoom - pS->rXShift;
  9294. }
  9295. return ax;
  9296. }
  9297. /* Slicer_yCanvasToActual */
  9298. static double Slicer_yCanvasToActual(Slicer *p,struct OneSlice *pS, double cy){
  9299. double ay;
  9300. if(p->nSlice==1) {
  9301. ay=-cy*p->rZoom;
  9302. } else {
  9303. ay = pS->mxY + (pS->mnY-pS->mxY)*(cy-pS->top)/(pS->btm-pS->top);
  9304. }
  9305. return ay;
  9306. }
  9307. /* Slicer_xActualToCanvas */
  9308. static double Slicer_xActualToCanvas(Slicer *p,struct OneSlice *pS, double ax){
  9309. /*
  9310. ** Convert a X coordinate from actual to canvas coordinates for a
  9311. ** given deck.
  9312. */
  9313. double cx;
  9314. if(p->nSlice==1) {
  9315. cx = ax/p->rZoom;
  9316. } else {
  9317. cx = (ax+pS->rXShift)/p->rZoom;
  9318. }
  9319. return cx;
  9320. }
  9321. /* Slicer_yActualToCanvas */
  9322. static double Slicer_yActualToCanvas(Slicer *p,struct OneSlice *pS, double ay){
  9323. /*
  9324. ** Convert a Y coordinate from actual to canvas coordinates for a
  9325. ** given deck.
  9326. */
  9327. double cy;
  9328. if(p->nSlice==1) {
  9329. cy=-ay/p->rZoom;
  9330. } else {
  9331. cy = pS->top + (pS->btm-pS->top)*(ay-pS->mxY)/(pS->mnY-pS->mxY);
  9332. }
  9333. return cy;
  9334. }
  9335. /* Slicer_deckHeight */
  9336. static double Slicer_deckHeight(struct OneSlice *p, double rX){
  9337. /*
  9338. ** Return the height above baseline for the deck location rX.
  9339. */
  9340. int i;
  9341. double *xz;
  9342. if(!p) {
  9343. return 0.0;
  9344. }
  9345. if( p->nXZ<4 ){
  9346. return p->z;
  9347. }
  9348. xz = p->xz;
  9349. if( rX<=xz[0] ){
  9350. return xz[1];
  9351. }
  9352. for(i=2; i<p->nXZ; i+=2){
  9353. if( rX<=xz[i] ){
  9354. assert( xz[i]>xz[i-2] );
  9355. return xz[i-1] + (xz[i+1]-xz[i-1])*(rX-xz[i-2])/(xz[i]-xz[i-2]);
  9356. }
  9357. }
  9358. return xz[p->nXZ-1];
  9359. }
  9360. /* *Slicer_deckAt */
  9361. static struct OneSlice *Slicer_deckAt(Slicer *p, double rX, double rZ){
  9362. /*
  9363. ** Return a pointer to the particular deck at actual coordinates
  9364. ** X, Z
  9365. */
  9366. int i;
  9367. struct OneSlice *pBest;
  9368. double bestHeight;
  9369. if( p->nSlice==0 ) return 0;
  9370. pBest = &p->a[0];
  9371. bestHeight = Slicer_deckHeight(pBest, rX);
  9372. for(i=1; i<p->nSlice; i++){
  9373. double dh = Slicer_deckHeight(&p->a[i],rX);
  9374. if( dh>bestHeight && dh<=rZ ){
  9375. pBest = &p->a[i];
  9376. bestHeight = dh;
  9377. }
  9378. }
  9379. return pBest;
  9380. }
  9381. /* *Slicer_deckAbove */
  9382. static struct OneSlice *Slicer_deckAbove(Slicer *p, struct OneSlice *pRef){
  9383. /*
  9384. ** Return a pointer to the deck immediately above the given deck.
  9385. ** Return NULL if the given deck is topmost.
  9386. */
  9387. int i;
  9388. struct OneSlice *pBest = 0;
  9389. if( p->nSlice==0 ) return 0;
  9390. for(i=0; i<p->nSlice; i++){
  9391. struct OneSlice *pTest = &p->a[i];
  9392. if( pTest->z<=pRef->z ) continue;
  9393. if( pBest==0 || pBest->z>pTest->z ){
  9394. pBest = pTest;
  9395. }
  9396. }
  9397. return pBest;
  9398. }
  9399. /* *Slicer_deckBelow */
  9400. static struct OneSlice *Slicer_deckBelow(Slicer *p, struct OneSlice *pRef){
  9401. /*
  9402. ** Return a pointer to the deck immediately above the given deck.
  9403. ** Return NULL if the given deck is topmost.
  9404. */
  9405. int i;
  9406. struct OneSlice *pBest = 0;
  9407. if( p->nSlice==0 ) return 0;
  9408. for(i=0; i<p->nSlice; i++){
  9409. struct OneSlice *pTest = &p->a[i];
  9410. if( pTest->z>=pRef->z ) continue;
  9411. if( pBest==0 || pBest->z<pTest->z ){
  9412. pBest = pTest;
  9413. }
  9414. }
  9415. return pBest;
  9416. }
  9417. /* Slicer_computeTopAndBottom */
  9418. static void Slicer_computeTopAndBottom(Slicer *p){
  9419. /*
  9420. ** Recompute the values of p->a[].top and p->a[].btm for all slices in
  9421. ** the given slicer.
  9422. */
  9423. int i;
  9424. double rY = 0.0;
  9425. double rBound = -9.9e99;
  9426. for(i=p->nSlice-1; i>=0; i--){
  9427. double h = (p->a[i].mxY - p->a[i].mnY)/p->rZoom;
  9428. p->a[i].upperbound = rBound;
  9429. p->a[i].top = rY;
  9430. p->a[i].btm = rY + h;
  9431. rY = p->a[i].btm + 0.3*h;
  9432. rBound = p->a[i].btm + 0.15*h;
  9433. }
  9434.  
  9435. if( p->nSlice==0 ) return;
  9436.  
  9437. /* Calculate the above and below for each deck */
  9438.  
  9439. for(i=0; i<p->nSlice; i++){
  9440. struct OneSlice *pThis = &p->a[i];
  9441. struct OneSlice *pBest = 0;
  9442.  
  9443. pBest=Slicer_deckAbove(p,pThis);
  9444. if(pBest) {
  9445. pThis->above=pBest->did;
  9446. } else {
  9447. pThis->above=0;
  9448. }
  9449. pBest=Slicer_deckBelow(p,pThis);
  9450. if(pBest) {
  9451. pThis->below=pBest->did;
  9452. } else {
  9453. pThis->below=0;
  9454. }
  9455. }
  9456. }
  9457. /* Slicer_getDeck */
  9458. static int Slicer_getDeck(
  9459. Tcl_Interp *interp, /* Put error messages here */
  9460. Slicer *p, /* The slicer */
  9461. double rX, /* X coord used to find deck if pObj is a Z coord */
  9462. Tcl_Obj *pObj, /* Either a deck name or a Z coordinate */
  9463. struct OneSlice **ppS /* Write the slice pointer here */
  9464. ){
  9465. /*
  9466. ** pObj is either the name of a deck or a Z coordinate. If it is a
  9467. ** deck name, find the deck and write a pointer to it in *ppS. If
  9468. ** it is a Z coordinate, use that coordinate together with rX to
  9469. ** find the deck and write it into *ppS. If an error occurs, put
  9470. ** an error message on the TCL interpreter and return TCL_ERROR.
  9471. ** Return TCL_OK on success.
  9472. */
  9473. double rZ;
  9474. const char *zName;
  9475. int i;
  9476. if(p->nSlice==1) {
  9477. *ppS=&p->a[0];
  9478. return TCL_OK;
  9479. }
  9480. if( Tcl_GetDoubleFromObj(0, pObj, &rZ)==TCL_OK ){
  9481. *ppS = Slicer_deckAt(p, rX, rZ);
  9482. return TCL_OK;
  9483. }
  9484. zName = Tcl_GetStringFromObj(pObj, 0);
  9485. for(i=0; i<p->nSlice; i++){
  9486. if( strcmp(zName, p->a[i].zName)==0 ){
  9487. *ppS = &p->a[i];
  9488. return TCL_OK;
  9489. }
  9490. }
  9491. Tcl_AppendResult(interp, "no such deck: ", zName, 0);
  9492. return TCL_ERROR;
  9493. }
  9494. /* Slicer_getDeckId */
  9495. static int Slicer_getDeckId(
  9496. Tcl_Interp *interp, /* Put error messages here */
  9497. Slicer *p, /* The slicer */
  9498. Tcl_Obj *pObj, /* Either a deck name or a Z coordinate */
  9499. struct OneSlice **ppS /* Write the slice pointer here */
  9500. ){
  9501. /*
  9502. ** pObj is either the name of a deck or a Z coordinate. If it is a
  9503. ** deck name, find the deck and write a pointer to it in *ppS. If
  9504. ** it is a Z coordinate, use that coordinate together with rX to
  9505. ** find the deck and write it into *ppS. If an error occurs, put
  9506. ** an error message on the TCL interpreter and return TCL_ERROR.
  9507. ** Return TCL_OK on success.
  9508. */
  9509. int did;
  9510. const char *zName;
  9511. int i;
  9512. if(p->nSlice==1) {
  9513. *ppS=&p->a[0];
  9514. return TCL_OK;
  9515. }
  9516. if( Tcl_GetIntFromObj(interp, pObj, &did)==TCL_OK ){
  9517. for(i=0; i<p->nSlice; i++){
  9518. if( did == p->a[i].did ){
  9519. *ppS = &p->a[i];
  9520. return TCL_OK;
  9521. }
  9522. }
  9523. Tcl_AppendResult(interp, "no such deckid: ", 0);
  9524. return TCL_ERROR;
  9525. }
  9526. zName = Tcl_GetStringFromObj(pObj, 0);
  9527. for(i=0; i<p->nSlice; i++){
  9528. if( strcmp(zName, p->a[i].zName)==0 ){
  9529. *ppS = &p->a[i];
  9530. return TCL_OK;
  9531. }
  9532. }
  9533. Tcl_AppendResult(interp, "no such deck: ", zName, 0);
  9534. return TCL_ERROR;
  9535. }
  9536. /* *Slicer_GetSlicerFromObj */
  9537. Slicer *Slicer_GetSlicerFromObj(Tcl_Interp *interp,Tcl_Obj *tclobj){
  9538. Tcl_Object pObj;
  9539. Slicer *pSlicer=NULL;
  9540. pObj=Tcl_GetObjectFromObj(interp,tclobj);
  9541. if(!pObj) {
  9542. return NULL;
  9543. }
  9544. pSlicer=(Slicer *)Tcl_ObjectGetMetadata(pObj,&SlicerDataType);
  9545. return pSlicer;
  9546. }
  9547. /* *Slicer_getDeck_FromInt */
  9548. static inline struct OneSlice *Slicer_getDeck_FromInt(
  9549. Slicer *p,
  9550. int did
  9551. ){
  9552. int i;
  9553. if(p->nSlice==1) {
  9554. return &p->a[0];
  9555. }
  9556. for(i=0; i<p->nSlice; i++){
  9557. if( did == p->a[i].did ){
  9558. return &p->a[i];
  9559. }
  9560. }
  9561. return NULL;
  9562. }
  9563. /* slicer_drawline_do */
  9564. static int slicer_drawline_do(
  9565. Tcl_Interp *interp,
  9566. Slicer *p,
  9567. int coord_count,
  9568. int *deckCoord,double *xCoord,double *yCoord,
  9569. struct OneSlice **apDeck,
  9570. Tcl_Obj *canvas,
  9571. const char *zKTag,
  9572. const char *zXTag,
  9573. const char *zBTag
  9574. ){
  9575. int i;
  9576.  
  9577. Tcl_Obj *pVTag; /* The "sNNN" tag added to all line segments */
  9578.  
  9579. Tcl_Obj *aLineArg[20]; /* Element of "create line" TCL command */
  9580. int nLineArg; /* Number of used entries in aLineArg[] */
  9581. Tcl_Obj *aBendArg[20]; /* Cmd to bends penetractions */
  9582. int nBendArg;
  9583.  
  9584. nBendArg = 0;
  9585. if(zBTag) {
  9586. aBendArg[0] = canvas;
  9587. aBendArg[1] = ODIE_CONSTANT_STRING("create");
  9588. aBendArg[2] = ODIE_CONSTANT_STRING("oval");
  9589. for(i=3; i<=6; i++){
  9590. aBendArg[i] = Tcl_NewObj();
  9591. }
  9592. aBendArg[7] = ODIE_CONSTANT_STRING("-tags");
  9593. for(i=0; i<=7; i++){
  9594. Tcl_IncrRefCount(aBendArg[i]);
  9595. }
  9596. nBendArg = 9;
  9597. }
  9598. aLineArg[0] = canvas;
  9599. aLineArg[1] = ODIE_CONSTANT_STRING("create");
  9600. aLineArg[2] = ODIE_CONSTANT_STRING("line");
  9601. for(i=3; i<=6; i++){
  9602. aLineArg[i] = Tcl_NewObj();
  9603. }
  9604. aLineArg[7] = ODIE_CONSTANT_STRING("-tags");
  9605. for(i=0; i<=7; i++){
  9606. Tcl_IncrRefCount(aLineArg[i]);
  9607. }
  9608. nLineArg = 9;
  9609.  
  9610.  
  9611.  
  9612. for(i=1; i<coord_count; i++){
  9613. char zBuf[30];
  9614. double x0, y0, x1, y1;
  9615.  
  9616. x0 = Slicer_xActualToCanvas(p,apDeck[i-1],xCoord[i-1]);
  9617. x1 = Slicer_xActualToCanvas(p,apDeck[i],xCoord[i]);
  9618. y0 = Slicer_yActualToCanvas(p,apDeck[i-1],yCoord[i-1]);
  9619. y1 = Slicer_yActualToCanvas(p,apDeck[i], yCoord[i]);
  9620. Tcl_SetDoubleObj(aLineArg[3], x0);
  9621. Tcl_SetDoubleObj(aLineArg[4], y0);
  9622. Tcl_SetDoubleObj(aLineArg[5], x1);
  9623. Tcl_SetDoubleObj(aLineArg[6], y1);
  9624. if( apDeck[i]!=apDeck[i-1] && zXTag ){
  9625. sprintf(zBuf, "%s s%d", zXTag, i);
  9626. } else {
  9627. sprintf(zBuf, "%s s%d", zKTag, i);
  9628. }
  9629. pVTag = Tcl_NewStringObj(zBuf, -1);
  9630. Tcl_IncrRefCount(pVTag);
  9631. aLineArg[8]=pVTag;
  9632.  
  9633. if(i<(coord_count-1) && nBendArg) {
  9634. char bBuf[30];
  9635. Tcl_Obj *pBTag; /* The "nNNN" tag added to all line bend points */
  9636. sprintf(bBuf, "%s b%d", zBTag, i);
  9637. pBTag = Tcl_NewStringObj(bBuf, -1);
  9638. Tcl_IncrRefCount(pVTag);
  9639. Tcl_SetDoubleObj(aBendArg[3], x1-4);
  9640. Tcl_SetDoubleObj(aBendArg[4], y1-4);
  9641. Tcl_SetDoubleObj(aBendArg[5], x1+4);
  9642. Tcl_SetDoubleObj(aBendArg[6], y1+4);
  9643. aBendArg[8] = pBTag;
  9644. Tcl_EvalObjv(interp, nBendArg, aBendArg, 0);
  9645. }
  9646. Tcl_EvalObjv(interp, nLineArg, aLineArg, 0);
  9647. }
  9648. for(i=0; i<=7; i++){
  9649. Tcl_DecrRefCount(aLineArg[i]);
  9650. if( i<nBendArg ) Tcl_DecrRefCount(aBendArg[i]);
  9651. }
  9652. for(i=9; i<nLineArg; i++){
  9653. Tcl_DecrRefCount(aLineArg[i]);
  9654. }
  9655. for(i=9; i<nBendArg; i++){
  9656. Tcl_DecrRefCount(aBendArg[i]);
  9657. }
  9658. return TCL_OK;
  9659. }
  9660. /* Slicer_Location_zabs */
  9661. static inline double Slicer_Location_zabs(Slicer *p,struct OneSlice *pS,double x0,double dheight){
  9662. struct OneSlice *pAbove;
  9663. if(dheight >= 0) {
  9664. return dheight+Slicer_deckHeight(pS,x0);
  9665. }
  9666. pAbove=Slicer_deckAbove(p,pS);
  9667. if(pAbove) {
  9668. return Slicer_deckHeight(pAbove,x0)+dheight;
  9669. }
  9670. return Slicer_deckHeight(pS,x0)+p->upper_height+dheight;
  9671. }
  9672. /* Location_zdeck */
  9673. static inline double Location_zdeck(Slicer *p,struct OneSlice *pS,double x0,double dheight){
  9674. struct OneSlice *pAbove;
  9675. if(dheight >= 0) {
  9676. return dheight;
  9677. }
  9678. pAbove=Slicer_deckAbove(p,pS);
  9679. if(pAbove) {
  9680. return Slicer_deckHeight(pAbove,x0)-Slicer_deckHeight(pS,x0)+dheight;
  9681. }
  9682. return p->upper_height+dheight;
  9683. }
  9684. /* Slicer_Find_Deckid_And_Offset */
  9685. int Slicer_Find_Deckid_And_Offset(Slicer *pSlicer,double x0,double y0,double z0,int *deckid,double *zoff){
  9686. struct OneSlice *ppS,*pAbove;
  9687. double zdeck;
  9688. *zoff=0.0;
  9689. *deckid=0;
  9690. if(!pSlicer) {
  9691. return TCL_ERROR;
  9692. }
  9693. ppS=Slicer_deckAt(pSlicer,x0,z0);
  9694. if(!ppS) {
  9695. return TCL_ERROR;
  9696. }
  9697. *deckid=ppS->did;
  9698. zdeck=Slicer_deckHeight(ppS,x0);
  9699. *zoff=z0-zdeck;
  9700. return TCL_OK;
  9701. }
  9702. /* Slicer_Absolute_Z */
  9703. double Slicer_Absolute_Z(Slicer *pSlicer,int deckid,double x0,double y0,double zoff){
  9704. struct OneSlice *ppS,*pAbove;
  9705. double zresult=0.0;
  9706. if(!pSlicer) {
  9707. return 0;
  9708. }
  9709. ppS=Slicer_getDeck_FromInt(pSlicer,deckid);
  9710. if(!ppS) {
  9711. return 0;
  9712. }
  9713. if(zoff < 0.0) {
  9714. pAbove = Slicer_deckAbove(pSlicer, ppS);
  9715. if(pAbove) {
  9716. zresult=Slicer_deckHeight(pAbove,x0)+zoff;
  9717. } else {
  9718. zresult=Slicer_deckHeight(ppS,x0)+2000+zoff;
  9719. }
  9720. } else {
  9721. zresult=Slicer_deckHeight(ppS,x0)+zoff;
  9722. }
  9723. return zresult;
  9724. }
  9725. /*
  9726. ** This file implements a TCL object that keeps track of the walls and
  9727. ** bulkheads on a single deck of a ship.
  9728. **
  9729. ** This widget assumes a right-handed coordinate system if zoom is positive
  9730. ** and a left-handed coordinate system is zoom is negative. The Tk canvas
  9731. ** widget uses a left-handed coordinate system all the time. The READI
  9732. ** database uses a right-handed coordinate system all the time. This module
  9733. ** can be used to translate by setting zoom to +1.0 for database I/O and
  9734. ** to -$g(zoom) for canvas I/O.
  9735. **
  9736. ** This module uses a purely 2-D model. It can only handle a single
  9737. ** deck at a time. If a multi-deck model needs to be displayed then
  9738. ** that multi-deck model should first be flattened into a stack of
  9739. ** individual decks in the same plane using the separate "slicer" object.
  9740. **
  9741. ** This file implements a single new constructor tcl command named "wallset".
  9742. ** The wallset command creates a new wallset object. Methods on this
  9743. ** wallset object are used to manage the object.
  9744. **
  9745. ** The details of the various methods and what they do are provided in
  9746. ** header comments above the implementation of each method.
  9747. */
  9748. #ifndef M_PI
  9749. # define M_PI 3.1415926535898
  9750. #endif
  9751.  
  9752. /*
  9753. ** Remove all of the ComptBox entries from the wallset.
  9754. */
  9755. static void clearComptBoxCache(Wallset *pWS){
  9756. ComptBox *p = pWS->pComptBox;
  9757. while( p ){
  9758. ComptBox *pNext = p->pNext;
  9759. Tcl_Free((char *)p);
  9760. p = pNext;
  9761. }
  9762. pWS->pComptBox = 0;
  9763. }
  9764.  
  9765. /*
  9766. ** This routine is invoked when the TCL command that implements a
  9767. ** wallset is deleted. Free all memory associated with that
  9768. ** wallset.
  9769. */
  9770. static void destroyWallset(void *pArg){
  9771. Wallset *p = (Wallset*)pArg;
  9772. Link *pLink = p->pAll;
  9773. clearComptBoxCache(p);
  9774. while( pLink ){
  9775. Segment *pSeg = pLink->pLinkNode;
  9776. pLink = pSeg->pAll.pNext;
  9777. Tcl_Free((char *) pSeg );
  9778. }
  9779. Tcl_Free((char *) p );
  9780. }
  9781.  
  9782. /*
  9783. ** Clear the Segment.ignore flag on all segments within a wallset.
  9784. */
  9785. static void ignoreNone(Wallset *p){
  9786. #if 0
  9787. Link *pLink;
  9788. for(pLink=p->pAll; pLink; pLink=pLink->pNext){
  9789. pLink->pSeg->ignore = 0;
  9790. }
  9791. #endif
  9792. }
  9793.  
  9794. /*
  9795. ** Return a pointer to the segment with the given ID. Return NULL
  9796. ** if there is no such segment.
  9797. */
  9798. static Segment *findSegment(Wallset *p, int id){
  9799. int h;
  9800. Link *pLink;
  9801.  
  9802. h = hashInt(id);
  9803. for(pLink = p->hashId[h]; pLink; pLink=pLink->pNext){
  9804. Segment *pSeg=pLink->pLinkNode;
  9805. if( pSeg->id==id ) return pSeg;
  9806. }
  9807. return 0;
  9808. }
  9809.  
  9810. /*
  9811. ** Scan all segments looking for the vertex or vertices that are nearest
  9812. ** to x,y. Return a pointer to a Segment.set that is the list of matching
  9813. ** segments. Also write the nearest point into *pX,*pY.
  9814. **
  9815. ** The returned list uses the Segment.set link.
  9816. */
  9817. static Link *nearestVertex(
  9818. Wallset *p, /* The wallset to be scanned */
  9819. double x, double y, /* Search for points near to this point */
  9820. double *pX, double *pY /* Write nearest vertex here */
  9821. ){
  9822. double nx, ny;
  9823. double min = -1.0;
  9824. Link *pList = 0;
  9825. Link *pI;
  9826.  
  9827. nx = x = roundCoord(x);
  9828. ny = y = roundCoord(y);
  9829. for(pI=p->pAll; pI; pI=pI->pNext){
  9830. double dx, dy, dist;
  9831. Segment *pSeg = pI->pLinkNode;
  9832. dx = x - pSeg->from[X_IDX];
  9833. dy = y - pSeg->from[Y_IDX];
  9834. dist = dx*dx + dy*dy;
  9835. if( min<0.0 || dist<=min ){
  9836. if( min<0.0 || nx!=pSeg->from[X_IDX] || ny!=pSeg->from[Y_IDX] ){
  9837. pList = 0;
  9838. nx = pSeg->from[X_IDX];
  9839. ny = pSeg->from[Y_IDX];
  9840. min = dist;
  9841. }
  9842. LinkInit(pSeg->pSet, pSeg);
  9843. LinkInsert(&pList, &pSeg->pSet);
  9844. }
  9845. dx = x - pSeg->to[X_IDX];
  9846. dy = y - pSeg->to[Y_IDX];
  9847. dist = dx*dx + dy*dy;
  9848. if( dist<=min ){
  9849. if( nx!=pSeg->to[X_IDX] || ny!=pSeg->to[Y_IDX] ){
  9850. pList = 0;
  9851. nx = pSeg->to[X_IDX];
  9852. ny = pSeg->to[Y_IDX];
  9853. min = dist;
  9854. }
  9855. LinkInit(pSeg->pSet, pSeg);
  9856. LinkInsert(&pList, &pSeg->pSet);
  9857. }
  9858. }
  9859. *pX = nx;
  9860. *pY = ny;
  9861. return pList;
  9862. }
  9863.  
  9864. /*
  9865. ** Scan all segments looking for the point on a segment that is nearest
  9866. ** to x,y. Return a pointer to a Segment.set that is the list of matching
  9867. ** segments. This set might contain multiple members if the nearest point
  9868. ** is actually a vertex shared by two or more segments. Write the nearest
  9869. ** point into *pX, *pY.
  9870. **
  9871. ** /// Ignore any segment that has its Segment.ignore flag set. -- removed
  9872. **
  9873. ** The returned list uses the Segment.set list.
  9874. */
  9875. static Link *nearestPoint(
  9876. Wallset *p, /* The wallset to be scanned */
  9877. double x, double y, /* Search for points near to this point */
  9878. double *pX, double *pY /* Write nearest vertex here */
  9879. ){
  9880. double nx, ny;
  9881. double min = -1.0;
  9882. Link *pList = 0;
  9883. Link *pI;
  9884.  
  9885. nx = x = roundCoord(x);
  9886. ny = y = roundCoord(y);
  9887. for(pI=p->pAll; pI; pI=pI->pNext){
  9888. double dx, dy, dist;
  9889. Segment *pSeg;
  9890. double acx, acy; /* Vector from x0,y0 to x,y */
  9891. double abx, aby; /* Vector from x0,y0 to x1,y1 */
  9892. double rx, ry; /* Nearest point on x0,y0->to[X_IDX],y1 to x,y */
  9893. double r;
  9894.  
  9895. pSeg = pI->pLinkNode;
  9896. /* if( pSeg->ignore ) continue; */
  9897. acx = x - pSeg->from[X_IDX];
  9898. acy = y - pSeg->from[Y_IDX];
  9899. abx = pSeg->to[X_IDX] - pSeg->from[X_IDX];
  9900. aby = pSeg->to[Y_IDX] - pSeg->from[Y_IDX];
  9901. r = (acx*abx + acy*aby)/(abx*abx + aby*aby);
  9902. if( r<=0 ){
  9903. rx = pSeg->from[X_IDX];
  9904. ry = pSeg->from[Y_IDX];
  9905. }else if( r>=1 ){
  9906. rx = pSeg->to[X_IDX];
  9907. ry = pSeg->to[Y_IDX];
  9908. }else{
  9909. rx = pSeg->from[X_IDX] + abx*r;
  9910. ry = pSeg->from[Y_IDX] + aby*r;
  9911. }
  9912. rx = roundCoord(rx);
  9913. ry = roundCoord(ry);
  9914. dx = x - rx;
  9915. dy = y - ry;
  9916. dist = dx*dx + dy*dy;
  9917. if( min<0.0 || dist<=min ){
  9918. if( min<0.0 || nx!=rx || ny!=ry ){
  9919. pList = 0;
  9920. nx = rx;
  9921. ny = ry;
  9922. min = dist;
  9923. }
  9924. LinkInit(pSeg->pSet, pSeg);
  9925. LinkInsert(&pList, &pSeg->pSet);
  9926. }
  9927. }
  9928. *pX = nx;
  9929. *pY = ny;
  9930. return pList;
  9931. }
  9932.  
  9933. /*
  9934. ** Return TRUE if the value x is in between x1 and x2.
  9935. */
  9936. static int between(double x, double x1, double x2){
  9937. if( x1<x2 ){
  9938. return x>=x1 && x<=x2;
  9939. }else{
  9940. return x>=x2 && x<=x1;
  9941. }
  9942. }
  9943.  
  9944. /*
  9945. ** Return TRUE if the given segment is on the given list
  9946. */
  9947. static int segmentOnList(Segment *pSeg, Link *pList){
  9948. while( pList ){
  9949. if( pList->pLinkNode==pSeg ) return 1;
  9950. pList = pList->pNext;
  9951. }
  9952. return 0;
  9953. }
  9954.  
  9955. /*
  9956. ** Return a list of all segments which have an end at the given vertex.
  9957. ** The returned list uses Segment.set
  9958. */
  9959. static Link *segmentsAtVertex(Wallset *p, double x, double y){
  9960. Link *pList = 0;
  9961. Link *pI;
  9962. int h;
  9963.  
  9964. x = roundCoord(x);
  9965. y = roundCoord(y);
  9966. h = hashCoord(x, y);
  9967. for(pI=p->hashFrom[h]; pI; pI=pI->pNext){
  9968. Segment *pSeg = pI->pLinkNode;
  9969. /* if( pSeg->ignore ) continue; */
  9970. if( floatCompare(x, pSeg->from[X_IDX])==0 && floatCompare(y, pSeg->from[Y_IDX])==0 ){
  9971. assert( !segmentOnList(pSeg, pList) );
  9972. LinkInit(pSeg->pSet, pSeg);
  9973. LinkInsert(&pList, &pSeg->pSet);
  9974. }
  9975. }
  9976. for(pI=p->hashTo[h]; pI; pI=pI->pNext){
  9977. Segment *pSeg = pI->pLinkNode;
  9978. /* if( pSeg->ignore ) continue; */
  9979. if( floatCompare(x, pSeg->to[X_IDX])==0 && floatCompare(y, pSeg->to[Y_IDX])==0 ){
  9980. assert( !segmentOnList(pSeg, pList) );
  9981. LinkInit(pSeg->pSet, pSeg);
  9982. LinkInsert(&pList, &pSeg->pSet);
  9983. }
  9984. }
  9985. return pList;
  9986. }
  9987.  
  9988. /*
  9989. ** The point xV,yV is a vertex in the wallset. This routine locates
  9990. ** a segment connected to that vertex which is the first segment in
  9991. ** a clockwise direction from xR,yR->xV,yV. A pointer to the segment
  9992. ** is written into *ppSeg. If the output segment moves backwards
  9993. ** (in other words if x1,y1 of the segment is connected at xV,yV)
  9994. ** then *pfBack is true.
  9995. **
  9996. ** If a suitable segment is found, 0 is returned. Non-zero is returned
  9997. ** if no suitable segment could be found.
  9998. **
  9999. ** This routine uses the Segment.set list internally.
  10000. */
  10001. static int nextCwSegment(
  10002. Wallset *p, /* The wallset */
  10003. double xR, double yR, /* Remote end of input segment */
  10004. double xV, double yV, /* Vertex (near end of input segment) */
  10005. Segment **ppSeg, /* OUT: First segment clockwise from xR,yR->xV,yV */
  10006. int *pfBack /* OUT: True if output segment goes backwards */
  10007. ){
  10008. Link *pList, *pI;
  10009. double rRef, rBest;
  10010. int i, nSeg, iBest;
  10011. Segment *pSeg;
  10012. struct {
  10013. Segment *pSeg;
  10014. int isBack;
  10015. double rAngle;
  10016. } *aSeg, aSegStatic[20];
  10017.  
  10018. /* Find all segments at xV,yV */
  10019. pList = segmentsAtVertex(p, xV, yV);
  10020. for(pI=pList, nSeg=0; pI; nSeg++, pI=pI->pNext){}
  10021. if( nSeg==0 ) return 1;
  10022. if( nSeg<=sizeof(aSegStatic)/sizeof(aSegStatic[0]) ){
  10023. aSeg = aSegStatic;
  10024. }else{
  10025. aSeg = (void *)Odie_Alloc( nSeg*sizeof(*aSeg) );
  10026. }
  10027. for(pI=pList, i=0; pI; i++, pI=pI->pNext){
  10028. aSeg[i].pSeg = pSeg = pI->pLinkNode;
  10029. aSeg[i].isBack = floatCompare(xV, pSeg->to[X_IDX])==0
  10030. && floatCompare(yV, pSeg->to[Y_IDX])==0;
  10031. }
  10032.  
  10033. /* Find the reference angle */
  10034. rRef = atan2(yR-yV, xR-xV)*180.0/M_PI;
  10035.  
  10036. /* Find angles on all segments */
  10037. for(i=0; i<nSeg; i++){
  10038. pSeg = aSeg[i].pSeg;
  10039. if( aSeg[i].isBack ){
  10040. aSeg[i].rAngle = atan2(pSeg->from[Y_IDX]-pSeg->to[Y_IDX], pSeg->from[X_IDX]-pSeg->to[X_IDX])*180.0/M_PI;
  10041. }else{
  10042. aSeg[i].rAngle = atan2(pSeg->to[Y_IDX]-pSeg->from[Y_IDX], pSeg->to[X_IDX]-pSeg->from[X_IDX])*180.0/M_PI;
  10043. }
  10044. }
  10045.  
  10046. /* Subtract 360 to any segment angle that is less than the reference angle */
  10047. for(i=0; i<nSeg; i++){
  10048. if( aSeg[i].rAngle<rRef ) aSeg[i].rAngle += 360;
  10049. }
  10050.  
  10051. /* Choose the segment with the largest angle */
  10052. rBest = aSeg[0].rAngle;
  10053. iBest = 0;
  10054. for(i=1; i<nSeg; i++){
  10055. if( aSeg[i].rAngle>rBest ){
  10056. iBest = i;
  10057. rBest = aSeg[i].rAngle;
  10058. }
  10059. }
  10060. *ppSeg = aSeg[iBest].pSeg;
  10061. *pfBack = aSeg[iBest].isBack;
  10062. if( aSeg!=aSegStatic ){
  10063. Tcl_Free((char *) aSeg );
  10064. }
  10065.  
  10066. return 0;
  10067. }
  10068.  
  10069. /*
  10070. ** Consider a line beginning at x0,y0 then going from x1,y1 to x2,y2.
  10071. ** x1,y1 is an elbow in the line. This routine returns -1 if the
  10072. ** elbow bends to the right, and +1 if it bends to the left. zero is
  10073. ** returned if the elbow does not bend at all.
  10074. */
  10075. static int bendDirection(
  10076. double x0, double y0,
  10077. double x1, double y1,
  10078. double x2, double y2
  10079. ){
  10080. /* Algorithm: Rotate x0,y0->to[X_IDX],y1 90 degrees counter-clockwise. Take
  10081. ** the dot product with x1,y1->x2,y2. The dot produce will be the product
  10082. ** of two (non-negative) magnitudes and the cosine of the angle. So if
  10083. ** the dot product is positive, the bend is to the left, or to the right if
  10084. ** the dot product is negative.
  10085. */
  10086. double r = (y0-y1)*(x2-x1) + (x1-x0)*(y2-y1);
  10087. return r<0.0 ? +1 : (r>0.0 ? -1 : 0);
  10088. }
  10089.  
  10090. /*
  10091. ** Given an interior point xI,yI, this routine finds a segment on the
  10092. ** boundary that contains the interior point. That segment is returned
  10093. ** in *ppSeg. *pfLeft is set to true if the interior point is to the left
  10094. ** of the segment and false if it is to the right.
  10095. **
  10096. ** Zero is returned on success. Non-zero is returned if no suitable
  10097. ** boundary could be located. Non-zero might be returned, for example,
  10098. ** if xI,yI is positioned directly on top of a wall or if there are no
  10099. ** walls in the wallset.
  10100. **
  10101. ** // Any segment marked with Segment.ignore is ignored for purposes of
  10102. ** // this routine. -- removed
  10103. **
  10104. ** This routine uses the Segment.set list internally.
  10105. */
  10106. static int firstBoundarySegment(
  10107. Wallset *p, /* The wallset */
  10108. double xI, double yI, /* An interior point */
  10109. Segment **ppSeg, /* OUT: A segment on the boundary containing xI,yI */
  10110. int *pfLeft /* OUT: True if xI,yI is to the left side *ppSeg */
  10111. ){
  10112. Link *pList;
  10113. double xN, yN;
  10114.  
  10115. /* Find nearest point, xN,yN */
  10116. pList = nearestPoint(p, xI, yI, &xN, &yN);
  10117. if( pList==0 ) return 1;
  10118. if( pList->pNext ){
  10119. /* xN,yN is a vertex...
  10120. ** Locate the first segment clockwise from xI,yI->xN,yN and return
  10121. */
  10122. return nextCwSegment(p, xI, yI, xN, yN, ppSeg, pfLeft);
  10123. }else{
  10124. /* xN,yN is a point on single line segment...
  10125. */
  10126. Segment *pSeg;
  10127. pSeg = *ppSeg = pList->pLinkNode;
  10128. *pfLeft = bendDirection(pSeg->from[X_IDX], pSeg->from[Y_IDX], xN, yN, xI, yI)>0;
  10129. }
  10130. return 0;
  10131. }
  10132.  
  10133. /*
  10134. ** Fill the given Boundary array with a list of segments (with
  10135. ** Segment.ignore set to false) that form a closed circuit. The
  10136. ** first entry in aBound[] has already been filled in by the
  10137. ** calling function and is used to seed the search.
  10138. **
  10139. ** At most nBound slots in aBound[] will be used. The return value
  10140. ** is the number of slots in aBound[] that would have been used if those
  10141. ** slots had been available. A return of 0 indicates that no boundary
  10142. ** is available.
  10143. **
  10144. ** If the checkIsPrimary flag is true and the aBound[0] entry is not
  10145. ** the primary segment for the compartment, then the aBound[] is not
  10146. ** completely filled in and the routine returns 0;
  10147. */
  10148. static int completeBoundary(
  10149. Wallset *p, /* The wallset */
  10150. int checkIsPrimary, /* Abort if aBound[0] is not the primary segment */
  10151. int nBound, /* Number of slots available in aBound[] */
  10152. Boundary *aBound /* IN-OUT: Write results into aBound[1...] */
  10153. ){
  10154. int cnt = 1;
  10155. Segment *pSeg, *pS;
  10156. int isLeft;
  10157. int isBack;
  10158. double xR, yR, xV, yV;
  10159.  
  10160. pS = pSeg = aBound[0].pSeg;
  10161. isLeft = aBound[0].backwards;
  10162. if( !isLeft ){
  10163. xR = pSeg->from[X_IDX];
  10164. yR = pSeg->from[Y_IDX];
  10165. xV = pSeg->to[X_IDX];
  10166. yV = pSeg->to[Y_IDX];
  10167. }else{
  10168. xV = pSeg->from[X_IDX];
  10169. yV = pSeg->from[Y_IDX];
  10170. xR = pSeg->to[X_IDX];
  10171. yR = pSeg->to[Y_IDX];
  10172. }
  10173. while( nextCwSegment(p,xR,yR,xV,yV,&pS,&isBack)==0 &&
  10174. (isBack!=isLeft || pS!=pSeg) ){
  10175. if( checkIsPrimary ){
  10176. if( pS->id<pSeg->id ) return 0;
  10177. if( pS->id==pSeg->id && !isLeft ) return 0;
  10178. }
  10179. if( isBack ){
  10180. xV = pS->from[X_IDX];
  10181. yV = pS->from[Y_IDX];
  10182. xR = pS->to[X_IDX];
  10183. yR = pS->to[Y_IDX];
  10184. }else{
  10185. xR = pS->from[X_IDX];
  10186. yR = pS->from[Y_IDX];
  10187. xV = pS->to[X_IDX];
  10188. yV = pS->to[Y_IDX];
  10189. }
  10190. if( nBound>cnt ){
  10191. aBound[cnt].pSeg = pS;
  10192. aBound[cnt].backwards = isBack;
  10193. }
  10194. cnt++;
  10195. if( cnt>1000 /* 00 */ ) return -cnt; /* Avoid an infinite loop */
  10196. }
  10197. return cnt;
  10198. }
  10199.  
  10200. /*
  10201. ** Compute the "spin" on a boundary. A positive value means the
  10202. ** circulation is to counter-clockwise and a negative value means the
  10203. ** circulation is clockwise. For boundaries, a positive
  10204. ** value means the region is internal and a negative value means
  10205. ** the region is external.
  10206. */
  10207. static double spin(Boundary *aBound, int nBound){
  10208. double sum = 0;
  10209. int i;
  10210. for(i=0; i<nBound; i++){
  10211. double x0, y0, x1, y1;
  10212. double dx, dy;
  10213. Segment *pSeg = aBound->pSeg;
  10214. if( aBound->backwards ){
  10215. x0 = pSeg->to[X_IDX];
  10216. y0 = pSeg->to[Y_IDX];
  10217. x1 = pSeg->from[X_IDX];
  10218. y1 = pSeg->from[Y_IDX];
  10219. }else{
  10220. x0 = pSeg->from[X_IDX];
  10221. y0 = pSeg->from[Y_IDX];
  10222. x1 = pSeg->to[X_IDX];
  10223. y1 = pSeg->to[Y_IDX];
  10224. }
  10225. aBound++;
  10226. dx = x1-x0;
  10227. dy = y1-y0;
  10228. sum += x0*dy - y0*dx;
  10229. }
  10230. return sum;
  10231. }
  10232.  
  10233. /*
  10234. ** The input is two linked lists of ComptBox structures where each
  10235. ** list is sorted by increasing area. Combine these two lists into
  10236. ** a single sorted linked list.
  10237. */
  10238. static ComptBox *mergeComptBox(ComptBox *p1, ComptBox *p2){
  10239. ComptBox head;
  10240. ComptBox *pTail = &head;
  10241. ComptBox *p;
  10242. while( p1 && p2 ){
  10243. if( p1->area<=p2->area ){
  10244. p = p1->pNext;
  10245. pTail->pNext = p1;
  10246. pTail = p1;
  10247. p1 = p;
  10248. }else{
  10249. p = p2->pNext;
  10250. pTail->pNext = p2;
  10251. pTail = p2;
  10252. p2 = p;
  10253. }
  10254. }
  10255. if( p1 ){
  10256. pTail->pNext = p1;
  10257. }else{
  10258. pTail->pNext = p2;
  10259. }
  10260. return head.pNext;
  10261. }
  10262.  
  10263. /*
  10264. ** Construct the ComptBox cache. For each compartment (where a compartment
  10265. ** is a closed circuit of Segments) make an entry on the Wallset.pComptBox
  10266. ** list.
  10267. **
  10268. ** If the ComptBox cache already exists, this routine is a no-op.
  10269. */
  10270. static void buildComptBoxCache(Wallset *p){
  10271. Link *pI;
  10272. int i;
  10273. ComptBox *aSort[30];
  10274.  
  10275. /* Return immediately if the cache already exists */
  10276. if( p->pComptBox ) return;
  10277.  
  10278. /* Compute a linked list of all compartment boxes */
  10279. for(pI=p->pAll; pI; pI=pI->pNext){
  10280. int i, j, n;
  10281. Boundary aBound[1000];
  10282.  
  10283. aBound[0].pSeg = pI->pLinkNode;
  10284. for(j=0; j<2; j++){
  10285. aBound[0].backwards = j;
  10286. n = completeBoundary(p, 1, sizeof(aBound)/sizeof(aBound[0]), aBound);
  10287. if( n>0 && spin(aBound,n)>0.0 ){
  10288. double dx, dy;
  10289. Segment *pSeg = pI->pLinkNode;
  10290. ComptBox *pNew = (ComptBox *)Odie_Alloc( sizeof(*pNew) );
  10291. pNew->pNext = p->pComptBox;
  10292. pNew->bbox[BBOX_X0_IDX] = pNew->bbox[BBOX_X1_IDX] = pSeg->from[X_IDX];
  10293. pNew->bbox[BBOX_Y1_IDX] = pNew->bbox[BBOX_Y0_IDX] = pSeg->from[Y_IDX];
  10294. pNew->prim = aBound[0];
  10295. for(i=1; i<n; i++){
  10296. Segment *pSeg = aBound[i].pSeg;
  10297. if( pSeg->from[X_IDX]<pNew->bbox[BBOX_X0_IDX] ) pNew->bbox[BBOX_X0_IDX] = pSeg->from[X_IDX];
  10298. if( pSeg->from[X_IDX]>pNew->bbox[BBOX_X1_IDX] ) pNew->bbox[BBOX_X1_IDX] = pSeg->from[X_IDX];
  10299. if( pSeg->from[Y_IDX]<pNew->bbox[BBOX_Y0_IDX] ) pNew->bbox[BBOX_Y0_IDX] = pSeg->from[Y_IDX];
  10300. if( pSeg->from[Y_IDX]>pNew->bbox[BBOX_Y1_IDX] ) pNew->bbox[BBOX_Y1_IDX] = pSeg->from[Y_IDX];
  10301. if( pSeg->to[X_IDX]<pNew->bbox[BBOX_X0_IDX] ) pNew->bbox[BBOX_X0_IDX] = pSeg->to[X_IDX];
  10302. if( pSeg->to[X_IDX]>pNew->bbox[BBOX_X1_IDX] ) pNew->bbox[BBOX_X1_IDX] = pSeg->to[X_IDX];
  10303. if( pSeg->to[Y_IDX]<pNew->bbox[BBOX_Y0_IDX] ) pNew->bbox[BBOX_Y0_IDX] = pSeg->to[Y_IDX];
  10304. if( pSeg->to[Y_IDX]>pNew->bbox[BBOX_Y1_IDX] ) pNew->bbox[BBOX_Y1_IDX] = pSeg->to[Y_IDX];
  10305. }
  10306. dx = pNew->bbox[BBOX_X1_IDX] - pNew->bbox[BBOX_X0_IDX];
  10307. dy = pNew->bbox[BBOX_Y1_IDX] - pNew->bbox[BBOX_Y0_IDX];
  10308. pNew->area = sqrt(dx*dx+dy*dy);
  10309. p->pComptBox = pNew;
  10310. }
  10311. }
  10312. }
  10313.  
  10314. /* Sort the list into order of increasing area */
  10315. for(i=0; i<sizeof(aSort)/sizeof(aSort[0]); i++) aSort[i] = 0;
  10316. while( p->pComptBox ){
  10317. ComptBox *pBox = p->pComptBox;
  10318. p->pComptBox = pBox->pNext;
  10319. pBox->pNext = 0;
  10320. for(i=0; i<sizeof(aSort)/sizeof(aSort[0])-1 && aSort[i]!=0; i++){
  10321. pBox = mergeComptBox(aSort[i], pBox);
  10322. aSort[i] = 0;
  10323. }
  10324. aSort[i] = mergeComptBox(aSort[i], pBox);
  10325. }
  10326. for(i=0; i<sizeof(aSort)/sizeof(aSort[0]); i++){
  10327. p->pComptBox = mergeComptBox(aSort[i], p->pComptBox);
  10328. }
  10329. }
  10330.  
  10331. /*
  10332. ** Test to see if the point x,y is contained within the given
  10333. ** boundary or is on the outside of the boundary.
  10334. */
  10335. static int pointWithinBoundary(
  10336. Boundary *aBound, /* The boundary */
  10337. int nBound, /* Number of segments in the boundary */
  10338. double x, double y /* The point to test */
  10339. ){
  10340. int inside = 0;
  10341. int i;
  10342. for(i=0; i<nBound; i++){
  10343. double x0, y0, x1, y1;
  10344. Segment *p = aBound[i].pSeg;
  10345. x0 = p->from[X_IDX];
  10346. y0 = p->from[Y_IDX];
  10347. x1 = p->to[X_IDX];
  10348. y1 = p->to[Y_IDX];
  10349. if( x0==x1 ) continue;
  10350. if( (x0>x && x1>x) || (x0<x && x1<x) ) continue;
  10351. if( y1 - (x1-x)*(y1-y0)/(x1-x0) >= y ) inside = !inside;
  10352. }
  10353. return inside;
  10354. }
  10355.  
  10356. /*
  10357. ** Find a boundary which contains xI, yI. If the size of the boundary
  10358. ** is set to 0, that means no such boundary exists.
  10359. */
  10360. static int findBoundary(
  10361. Wallset *p, /* The wallset */
  10362. double xI, double yI, /* A point that the boundary should be near */
  10363. int nBound, /* Number of slots available in aBound[] */
  10364. Boundary *aBound /* OUT: Write results here */
  10365. ){
  10366. int n = 0;
  10367. ComptBox *pBox;
  10368.  
  10369. buildComptBoxCache(p);
  10370. for(pBox=p->pComptBox; pBox; pBox=pBox->pNext){
  10371. if( xI<pBox->bbox[BBOX_X0_IDX] || xI>pBox->bbox[BBOX_X1_IDX] || yI<pBox->bbox[BBOX_Y0_IDX] || yI>pBox->bbox[BBOX_Y1_IDX] ) continue;
  10372. aBound[0] = pBox->prim;
  10373. n = completeBoundary(p, 0, nBound, aBound);
  10374. if( n>0 && pointWithinBoundary(aBound, n, xI, yI) ) break;
  10375. n = 0;
  10376. }
  10377. return n;
  10378. }
  10379.  
  10380.  
  10381. /*
  10382. ** Do an check of the integrity of the internal data structures. If
  10383. ** a problem is found, leave an error message in interp->result and
  10384. ** return TCL_ERROR. Return TCL_OK if everything is OK.
  10385. */
  10386. static int selfCheck(Tcl_Interp *interp, Wallset *p){
  10387. Link *pLink;
  10388. Segment *pSeg;
  10389. int h;
  10390. char zErr[200];
  10391.  
  10392. for(pLink=p->pAll; pLink; pLink=pLink->pNext){
  10393. pSeg = pLink->pLinkNode;
  10394. h = hashInt(pSeg->id);
  10395. if(!segmentOnList(pSeg, p->hashId[h]) ){
  10396. sprintf(zErr, "segment %d missing from hashId[%d]", pSeg->id, h);
  10397. Tcl_SetResult(interp, zErr, TCL_VOLATILE);
  10398. return TCL_ERROR;
  10399. }
  10400. h = hashCoord(pSeg->from[X_IDX], pSeg->from[Y_IDX]);
  10401. if(!segmentOnList(pSeg, p->hashFrom[h]) ){
  10402. sprintf(zErr, "segment %d missing from hashFrom[%d]", pSeg->id, h);
  10403. Tcl_SetResult(interp, zErr, TCL_VOLATILE);
  10404. return TCL_ERROR;
  10405. }
  10406. h = hashCoord(pSeg->to[X_IDX], pSeg->to[Y_IDX]);
  10407. if(!segmentOnList(pSeg, p->hashTo[h]) ){
  10408. sprintf(zErr, "segment %d missing from hashTo[%d]", pSeg->id, h);
  10409. Tcl_SetResult(interp, zErr, TCL_VOLATILE);
  10410. return TCL_ERROR;
  10411. }
  10412. }
  10413. return TCL_OK;
  10414. }
  10415.  
  10416. /*
  10417. ** The maximum number of segments in a boundary
  10418. */
  10419. #define MX_BOUND 1000
  10420.  
  10421. /* Wallset_Delete */
  10422. static void Wallset_Delete(ClientData clientData){
  10423. Wallset *p = (Wallset *)clientData;
  10424. Link *pLink = p->pAll;
  10425. clearComptBoxCache(p);
  10426. while( pLink ){
  10427. Segment *pSeg = pLink->pLinkNode;
  10428. pLink = pSeg->pAll.pNext;
  10429. Tcl_Free((char *) pSeg );
  10430. }
  10431. Tcl_Free((char *) p );
  10432. }
  10433. /* Wallset_Clone */
  10434. static int Wallset_Clone(
  10435. Tcl_Interp* interp, /* Tcl interpreter for error reporting */
  10436. ClientData metadata, /* Metadata to be cloned */
  10437. ClientData* newMetaData /* Where to put the cloned metadata */
  10438. ){
  10439. Tcl_SetObjResult(interp,
  10440. Tcl_NewStringObj("WALLSETs are not clonable", -1));
  10441. /* For now... */
  10442. return TCL_ERROR;
  10443. }
  10444. /* *PolygonHullVertex_ById */
  10445. static PolygonHullVertex *PolygonHullVertex_ById(PolygonHull *pHull, int id){
  10446. PolygonHullVertex *pVertex;
  10447. pVertex = (PolygonHullVertex*)readiHashFind(&pHull->VertexHash, 0, id);
  10448. return pVertex;
  10449. }
  10450. /* *PolygonHullVertex_ByCoords */
  10451. static PolygonHullVertex *PolygonHullVertex_ByCoords(PolygonHull *pHull, VectorXYZ A){
  10452. int h;
  10453. Link *pLink;
  10454. HashElem *i;
  10455. PolygonHullVertex *pVertex;
  10456. h = hashCoord3d(A[X_IDX],A[Y_IDX],A[X_IDX]);
  10457. for(pLink = pHull->VertexHashCoords[h]; pLink; pLink=pLink->pNext){
  10458. pVertex=pLink->pLinkNode;
  10459. if(VectorXYZ_SamePoint(pVertex->center,A)) {
  10460. return pVertex;
  10461. }
  10462. }
  10463. /* The hash checks sometimes miss. Search all */
  10464. for(i=readiHashFirst(&pHull->VertexHash); i; i=readiHashNext(i)) {
  10465. PolygonHullVertex *pVertex=(PolygonHullVertex *)readiHashData(i);
  10466. if(VectorXYZ_SamePoint(pVertex->center,A)) {
  10467. return pVertex;
  10468. }
  10469. }
  10470. return NULL;
  10471. }
  10472. /* *PolygonHullVertex_Create */
  10473. static PolygonHullVertex *PolygonHullVertex_Create(
  10474. PolygonHull *pHull,
  10475. int id,
  10476. VectorXYZ point
  10477. ){
  10478. int hx;
  10479. PolygonHullVertex *pVertex;
  10480. pVertex = (PolygonHullVertex *)Odie_Alloc( sizeof(PolygonHullVertex) );
  10481. if( pVertex==NULL ) return NULL;
  10482. if(id<0) {
  10483. pHull->VertexNextId++;
  10484. id=pHull->VertexNextId;
  10485. } else if (id>=pHull->VertexNextId) {
  10486. pHull->VertexNextId=id;
  10487. }
  10488. pVertex->id=id;
  10489. LinkInit(pVertex->pHashVertexCoords, pVertex);
  10490. readiHashInsert(&pHull->VertexHash, 0, id, pVertex);
  10491.  
  10492. pVertex->center[X_IDX]=point[X_IDX];
  10493. pVertex->center[Y_IDX]=point[Y_IDX];
  10494. pVertex->center[Z_IDX]=point[Z_IDX];
  10495. hx=hashCoord3d(point[X_IDX],point[Y_IDX],point[Z_IDX]);
  10496. LinkInsert(&pHull->VertexHashCoords[hx], &pVertex->pHashVertexCoords);
  10497. return pVertex;
  10498. }
  10499. /* PolygonHullVertex_Remove */
  10500. static void PolygonHullVertex_Remove(PolygonHullVertex *pVertex){
  10501. Link *pLink;
  10502. for(pLink=pVertex->pHashFace;pLink;pLink=pLink->pNext) {
  10503. PolygonHullFace *pFace=pLink->pLinkNode;
  10504. if(pFace) {
  10505. PolygonHullFace_Remove(pFace);
  10506. }
  10507. }
  10508. LinkRemove(&pVertex->pHashVertexCoords);
  10509. }
  10510. /* *PolygonHullFace_VertexInject */
  10511. static const char *PolygonHullFace_VertexInject(PolygonHullFace *pFace,PolygonHullVertex *pThisVertex){
  10512. PolygonHullVertex *pVertex,*pPrior=NULL,*pFirst;
  10513. PolygonHullFace_SerializeEdges(pFace);
  10514. pFirst=pFace->pNextVertex;
  10515. for(pVertex=pFirst;pVertex;pVertex=pVertex->pNextVertex) {
  10516. if(VectorXYZ_SamePoint(pVertex->center,pThisVertex->center)) {
  10517. /* Vertex already exists in polygon noop */
  10518. return NULL;
  10519. }
  10520. pPrior=pVertex;
  10521. }
  10522. for(pVertex=pFirst;pVertex;pVertex=pVertex->pNextVertex) {
  10523. if(VectorXYZ_PointIsOnSegment(pThisVertex->center,pPrior->center,pVertex->center)) {
  10524. pThisVertex->pNextVertex=pVertex;
  10525. if(pVertex==pFirst) {
  10526. /* Head Insert */
  10527. pFace->pNextVertex=pThisVertex;
  10528. return NULL;
  10529. } else {
  10530. /* Mid segment insert */
  10531. pPrior->pNextVertex=pThisVertex;
  10532. return NULL;
  10533. }
  10534. }
  10535. pPrior=pVertex;
  10536. }
  10537. /* Oh brother... */
  10538. return "Could not break edge";
  10539. }
  10540. /* *PolygonHullFace_To_Dict */
  10541. Tcl_Obj *PolygonHullFace_To_Dict(PolygonHullFace *pFace){
  10542. Tcl_Obj *element=Tcl_NewObj();
  10543. {
  10544. Tcl_Obj *value;
  10545. value=Tcl_NewIntObj(pFace->id);
  10546. Odie_DictObjPut(NULL,element,"id:",value);
  10547. }
  10548. {
  10549. Tcl_Obj *value;
  10550. value=Tcl_NewIntObj(pFace->nVertex);
  10551. Odie_DictObjPut(NULL,element,"nVertex:",value);
  10552. }
  10553. {
  10554. Tcl_Obj *value;
  10555. value=Tcl_NewIntObj(pFace->wallid);
  10556. Odie_DictObjPut(NULL,element,"wallid:",value);
  10557. }
  10558. {
  10559. Tcl_Obj *value;
  10560. value=Tcl_NewIntObj(pFace->deckid);
  10561. Odie_DictObjPut(NULL,element,"deckid:",value);
  10562. }
  10563. {
  10564. Tcl_Obj *value;
  10565. value=Tcl_NewIntObj(pFace->typeid);
  10566. Odie_DictObjPut(NULL,element,"typeid:",value);
  10567. }
  10568. {
  10569. Tcl_Obj *value;
  10570. value=Tcl_NewBooleanObj(pFace->is_wall);
  10571. Odie_DictObjPut(NULL,element,"is_wall:",value);
  10572. }
  10573. {
  10574. Tcl_Obj *value;
  10575. value=Tcl_NewBooleanObj(pFace->is_exterior);
  10576. Odie_DictObjPut(NULL,element,"is_exterior:",value);
  10577. }
  10578. {
  10579. Tcl_Obj *value;
  10580. value=Tcl_NewIntObj(pFace->is_virtual);
  10581. Odie_DictObjPut(NULL,element,"is_virtual:",value);
  10582. }
  10583. {
  10584. Tcl_Obj *value;
  10585. value=Tcl_NewIntObj(pFace->idLC);
  10586. Odie_DictObjPut(NULL,element,"idLC:",value);
  10587. }
  10588. {
  10589. Tcl_Obj *value;
  10590. value=Tcl_NewIntObj(pFace->idRC);
  10591. Odie_DictObjPut(NULL,element,"idRC:",value);
  10592. }
  10593. {
  10594. Tcl_Obj *value;
  10595. value=VectorXYZ_To_TclObj(pFace->center);
  10596. Odie_DictObjPut(NULL,element,"center:",value);
  10597. }
  10598. {
  10599. Tcl_Obj *value;
  10600. value=VectorXYZ_To_TclObj(pFace->normal);
  10601. Odie_DictObjPut(NULL,element,"normal:",value);
  10602. }
  10603. {
  10604. Tcl_Obj *value;
  10605. value=Tcl_NewDoubleObj(pFace->radius);
  10606. Odie_DictObjPut(NULL,element,"radius:",value);
  10607. }
  10608. {
  10609. Tcl_Obj *value;
  10610.  
  10611. char outbuf[64];
  10612. int i;
  10613. value=Tcl_NewObj();
  10614. for(i=0;i<6;i++) {
  10615. sprintf(outbuf,"%.3f",(float)pFace->bbox[i]);
  10616. Tcl_ListObjAppendElement(NULL,value,Tcl_NewStringObj(outbuf,-1));
  10617. }
  10618.  
  10619. Odie_DictObjPut(NULL,element,"bbox:",value);
  10620. }
  10621. return element;}
  10622. /* *PolygonHullFace_Create */
  10623. static PolygonHullFace *PolygonHullFace_Create(
  10624. PolygonHull *pHull,
  10625. int id
  10626. ){
  10627. PolygonHullFace *pFace;
  10628. pFace = (PolygonHullFace *)Odie_Alloc( sizeof(PolygonHullFace) );
  10629. if( pFace==NULL ) return NULL;
  10630. if(id<0) {
  10631. pHull->FaceNextId++;
  10632. id=pHull->FaceNextId;
  10633. } else if (id>=pHull->FaceNextId) {
  10634. pHull->FaceNextId=id;
  10635. }
  10636. pFace->id=id;
  10637. readiHashInsert(&pHull->FaceHash, 0, id, pFace);
  10638.  
  10639. pFace->id = id;
  10640. pFace->pActive = pHull->pActive;
  10641. pHull->pActive = pFace;
  10642.  
  10643. LinkInit(pFace->pSet, pFace);
  10644. return pFace;
  10645. }
  10646. /* *PolygonHull_mergeFaceList */
  10647. static PolygonHullFace *PolygonHull_mergeFaceList(PolygonHullFace *a, PolygonHullFace *b){
  10648. PolygonHullFace head, *pTail;
  10649. pTail = &head;
  10650. while( a && b ){
  10651. if( a->dist <= b->dist ){
  10652. pTail->pNext = a;
  10653. pTail = a;
  10654. a = a->pNext;
  10655. }else{
  10656. pTail->pNext = b;
  10657. pTail = b;
  10658. b = b->pNext;
  10659. }
  10660. }
  10661. if( a ){
  10662. pTail->pNext = a;
  10663. }else if( b ){
  10664. pTail->pNext = b;
  10665. }else{
  10666. pTail->pNext = 0;
  10667. }
  10668. return head.pNext;
  10669. }
  10670. /* *PolygonHull_sortFaceList */
  10671. static PolygonHullFace *PolygonHull_sortFaceList(PolygonHullFace *pList){
  10672. int i;
  10673. PolygonHullFace *p;
  10674. PolygonHullFace *ap[NBUCKET];
  10675. for(i=0; i<NBUCKET; i++){ ap[i] = 0; }
  10676. while( pList ){
  10677. p = pList;
  10678. pList = p->pNext;
  10679. p->pNext = 0;
  10680. for(i=0; i<NBUCKET-1; i++){
  10681. if( ap[i] ){
  10682. p = PolygonHull_mergeFaceList(ap[i], p);
  10683. ap[i] = 0;
  10684. }else{
  10685. ap[i] = p;
  10686. break;
  10687. }
  10688. }
  10689. if( i==NBUCKET ){
  10690. ap[i] = PolygonHull_mergeFaceList(ap[i],p);
  10691. }
  10692. }
  10693. p = 0;
  10694. for(i=0; i<NBUCKET; i++){
  10695. p = PolygonHull_mergeFaceList(ap[i], p);
  10696. }
  10697. return p;
  10698. }
  10699. /* *PolygonHullFace_ById */
  10700. static PolygonHullFace *PolygonHullFace_ById(PolygonHull *pHull, int id){
  10701. PolygonHullFace *pFace;
  10702. pFace = (PolygonHullFace*)readiHashFind(&pHull->FaceHash, 0, id);
  10703. return pFace;
  10704. }
  10705. /* PolygonHull_findFace */
  10706. static int PolygonHull_findFace(
  10707. Tcl_Interp *interp, /* Leave any error message here */
  10708. PolygonHull *pHull,
  10709. Tcl_Obj *pObj, /* The PolygonHullFace ID */
  10710. PolygonHullFace **ppHullFace /* Write PolygonHullFace pointer here */
  10711. ){
  10712. int id;
  10713. if( Tcl_GetIntFromObj(interp, pObj, &id) ) return TCL_ERROR;
  10714. *ppHullFace = PolygonHullFace_ById(pHull,id);
  10715. if( *ppHullFace==0 ){
  10716. Tcl_AppendResult(interp, "no such PolygonHullFace", 0);
  10717. return TCL_ERROR;
  10718. }
  10719. PolygonHullFace_Compute(*ppHullFace);
  10720. return TCL_OK;
  10721. }
  10722. /* PolygonHullFace_Remove */
  10723. static void PolygonHullFace_Remove(PolygonHullFace *pFace){
  10724. int i;
  10725. if(!pFace) return;
  10726. LinkRemove(&pFace->pSet);
  10727.  
  10728. if(pFace->aVertex) {
  10729. for(i=0;i<pFace->nVertex;i++) {
  10730. if(pFace->aVertex[i]==0) continue;
  10731. LinkRemove(&pFace->pVertex[i]);
  10732. }
  10733. Odie_Free((char *)pFace->aVertex);
  10734. }
  10735. if(pFace->pVertex) {
  10736. Odie_Free((char *)pFace->pVertex);
  10737. }
  10738. }
  10739. /* PolygonHullFace_SerializeEdges */
  10740. static void PolygonHullFace_SerializeEdges(PolygonHullFace *p){
  10741. int i;
  10742. PolygonHullVertex *pPrior=NULL,*pVertex;
  10743. if(p->pNextVertex) {
  10744. return;
  10745. }
  10746. //printf("PolygonHullFace_SerializeEdges %d %p\n",p->id,p->aVertex);
  10747. for(i=0;i<p->nVertex;i++) {
  10748. pVertex=p->aVertex[i];
  10749. assert(pVertex);
  10750. LinkRemove(&p->pVertex[i]);
  10751. //printf("PolygonHullFace_SerializeEdges %d #%d %p %p\n",p->id,i,pPrior,pVertex);
  10752. pVertex->pNextVertex=NULL;
  10753. if(!pPrior) {
  10754. p->pNextVertex=pVertex;
  10755. } else {
  10756. pPrior->pNextVertex=pVertex;
  10757. }
  10758. pPrior=pVertex;
  10759. }
  10760. //printf("PolygonHullFace_SerializeEdges %d LAST %d %p\n",p->id,i,pPrior);
  10761. if(pPrior) {
  10762. pPrior->pNextVertex=NULL;
  10763. }
  10764. Odie_Free(p->aVertex);
  10765. Odie_Free(p->pVertex);
  10766. p->nVertex=0;
  10767. p->aVertex=NULL;
  10768. p->pVertex=NULL;
  10769.  
  10770. }
  10771. /* PolygonHullFace_Compute */
  10772. static void PolygonHullFace_Compute(PolygonHullFace *pFace){
  10773. VectorXYZ one,two;
  10774. int i;
  10775. double r1,rmax;
  10776. int nVertex;
  10777. PolygonHullVertex *pVertex,*pFirst;
  10778. //printf("PolygonHullFace_Compute %d %p %p\n",pFace->id,pFace,pFace->pNextVertex);
  10779. if(!pFace->pNextVertex) {
  10780. return;
  10781. }
  10782. VectorXYZ_AABB_Reset(pFace->bbox);
  10783. nVertex=0;
  10784. /* Count the number of vertices */
  10785. pFirst=pFace->pNextVertex;
  10786. for(pVertex=pFirst;pVertex;pVertex=pVertex->pNextVertex) {
  10787. nVertex++;
  10788. if(nVertex>32) break;
  10789. }
  10790. pFace->nVertex=nVertex;
  10791. /* Allocate the arrays to store the vertices */
  10792. pFace->aVertex=(PolygonHullVertex **)Odie_Alloc(sizeof(PolygonHullVertex *)*pFace->nVertex);
  10793. pFace->pVertex=(Link *)Odie_Alloc(sizeof(Link)*pFace->nVertex);
  10794. pVertex=pFirst;
  10795. for(i=0;i<nVertex;i++) {
  10796. VectorXYZ_AABB_Measure(pVertex->center,pFace->bbox);
  10797. pFace->pNextVertex=pVertex->pNextVertex;
  10798. pFace->aVertex[i]=pVertex;
  10799. LinkInit(pFace->pVertex[i],pFace);
  10800. LinkInsert(&pVertex->pHashFace, &pFace->pVertex[i]);
  10801. pVertex=pVertex->pNextVertex;
  10802. }
  10803. for(i=0;i<nVertex;i++) {
  10804. pVertex=pFace->aVertex[i];
  10805. pVertex->pNextVertex=NULL;
  10806. }
  10807. if(pFace->nVertex==3) {
  10808. VectorXYZ_Subtract(one, pFace->aVertex[1]->center, pFace->aVertex[0]->center);
  10809. VectorXYZ_Subtract(two, pFace->aVertex[2]->center, pFace->aVertex[0]->center);
  10810. pFace->normal[X_IDX] = one[Y_IDX]*two[Z_IDX] - one[Z_IDX]*two[Y_IDX];
  10811. pFace->normal[Y_IDX] = one[Z_IDX]*two[X_IDX] - one[X_IDX]*two[Z_IDX];
  10812. pFace->normal[Z_IDX] = one[X_IDX]*two[Y_IDX] - one[Y_IDX]*two[X_IDX];
  10813. } else {
  10814. int i,j;
  10815. VectorXYZ_Zero(pFace->normal);
  10816. for(i=0,j=1;i<pFace->nVertex;i++,j++) {
  10817. if(j==pFace->nVertex) j=0;
  10818. pFace->normal[X_IDX] += (pFace->aVertex[j]->center[Y_IDX]-pFace->aVertex[i]->center[Y_IDX]) * (pFace->aVertex[j]->center[Z_IDX]+pFace->aVertex[i]->center[Z_IDX]);
  10819. pFace->normal[Y_IDX] += (pFace->aVertex[j]->center[Z_IDX]-pFace->aVertex[i]->center[Z_IDX]) * (pFace->aVertex[j]->center[X_IDX]+pFace->aVertex[i]->center[X_IDX]);
  10820. pFace->normal[Z_IDX] += (pFace->aVertex[j]->center[X_IDX]-pFace->aVertex[i]->center[X_IDX]) * (pFace->aVertex[j]->center[Y_IDX]+pFace->aVertex[i]->center[Y_IDX]);
  10821. }
  10822. }
  10823. VectorXYZ_Normalize(pFace->normal);
  10824. /* Compute the center and radius of the face. */
  10825. VectorXYZ_Zero(pFace->center);
  10826. for(i=0; i<pFace->nVertex; i++){
  10827. pFace->center[X_IDX] += pFace->aVertex[i]->center[X_IDX];
  10828. pFace->center[Y_IDX] += pFace->aVertex[i]->center[Y_IDX];
  10829. pFace->center[Z_IDX] += pFace->aVertex[i]->center[Z_IDX];
  10830. }
  10831. pFace->center[X_IDX] /= pFace->nVertex;
  10832. pFace->center[Y_IDX] /= pFace->nVertex;
  10833. pFace->center[Z_IDX] /= pFace->nVertex;
  10834. rmax=0.0;
  10835. for(i=0; i<pFace->nVertex; i++){
  10836. r1 = VectorXYZ_DistanceSq(pFace->center, pFace->aVertex[i]->center);
  10837. if(r1>rmax) {
  10838. rmax=r1;
  10839. }
  10840. }
  10841. pFace->radiusSq = rmax;
  10842. pFace->radius = sqrt(rmax);
  10843. }
  10844. /* PolygonHull_sqrDistPointToEdge */
  10845. static double PolygonHull_sqrDistPointToEdge(
  10846. VectorXYZ A, VectorXYZ B, /* End points of the line segment */
  10847. VectorXYZ X /* The point to measure distance to */
  10848. ){
  10849. VectorXYZ closest; /* Point on line segment closest to X */
  10850. VectorXYZ_ClosestPointOnSegment(A,B,X,closest);
  10851. return VectorXYZ_DistanceSq(X, closest);
  10852. }
  10853. /* PolygonHull_intersectLineSegFace */
  10854. static double PolygonHull_intersectLineSegFace(
  10855. PolygonHullFace *pFace, /* The triangle we are trying to intersect */
  10856. VectorXYZ pStart, /* Start of the line segment */
  10857. VectorXYZ pEnd, /* End of the line segment */
  10858. VectorXYZ pIntersect /* Point of intersection written here if not NULL */
  10859. ){
  10860. double d;
  10861. int i;
  10862. for(i=2;i<pFace->nVertex;i++) {
  10863. /*
  10864. ** Assuming we are fed convex polygons,
  10865. ** break the surface into triangles
  10866. ** and evaluate each triangle
  10867. */
  10868. d = VectorXYZ_TriangleLineIntersect(pFace->aVertex[0]->center,pFace->aVertex[i-1]->center,pFace->aVertex[i]->center,pStart,pEnd,pIntersect);
  10869. if(d>=0.0) {
  10870. return d;
  10871. }
  10872. }
  10873. return -1.0;
  10874. }
  10875. /* *PolygonHullFace_findHits */
  10876. static PolygonHullFace *PolygonHullFace_findHits(PolygonHull *pHull, VectorXYZ A, VectorXYZ B){
  10877. PolygonHullFace *p, *pList;
  10878. double d1, d2;
  10879. pList = 0;
  10880. for(p=pHull->pActive; p; p=p->pActive){
  10881. d1 = PolygonHull_sqrDistPointToEdge(A, B, p->center);
  10882. d2 = p->radiusSq;
  10883. if( d2<d1 ){
  10884. continue;
  10885. }
  10886. d1 = PolygonHull_intersectLineSegFace(p, A, B,p->intersect);
  10887. if( d1>=0.0 ){
  10888. p->pNext = pList;
  10889. pList = p;
  10890. p->dist = d1;
  10891. }
  10892. }
  10893. return PolygonHull_sortFaceList(pList);
  10894. }
  10895. /* PolygonHull_closestPointOnFace */
  10896. static double PolygonHull_closestPointOnFace(PolygonHullFace *p, VectorXYZ X, VectorXYZ R){
  10897. double d1, d2, distBest=1e99;
  10898. VectorXYZ testPt;
  10899. VectorXYZ a, b; /* End points of line seg parallel to p->normal */
  10900. int i,j;
  10901.  
  10902. /* Construct a line segment a->b that is parallel to p->normal and which
  10903. ** passes through X. Make sure the line segment is plenty long
  10904. ** enough so that it will intersect the plane of p.
  10905. */
  10906. d1 = VectorXYZ_Distance(X, p->center)*2;
  10907. d2 = p->normal[X_IDX]*d1;
  10908. a[X_IDX] = X[X_IDX] + d2;
  10909. b[X_IDX] = X[X_IDX] - d2;
  10910. d2 = p->normal[Y_IDX]*d1;
  10911. a[Y_IDX] = X[Y_IDX] + d2;
  10912. b[Y_IDX] = X[Y_IDX] - d2;
  10913. d2 = p->normal[Z_IDX]*d1;
  10914. a[Z_IDX] = X[Z_IDX] + d2;
  10915. b[Z_IDX] = X[Z_IDX] - d2;
  10916.  
  10917. /* Figure out if a->b intersects the triangle, and if so where. If
  10918. ** there is an intersection, then this is the closest point.
  10919. */
  10920. if( PolygonHull_intersectLineSegFace(p, a, b, R)>=0.0 ){
  10921. return VectorXYZ_Distance(X,R);
  10922. }
  10923.  
  10924. /*
  10925. ** If we reach here it means that the closest point will be on the
  10926. ** permiter of the triangle. There are three line faces on the
  10927. ** permiter. Try them all.
  10928. */
  10929. for(i=0,j=1;i<p->nVertex;i++,j++) {
  10930. if(j==p->nVertex) j=0;
  10931. VectorXYZ_ClosestPointOnSegment(p->aVertex[i]->center, p->aVertex[j]->center, X, testPt);
  10932. d1 = VectorXYZ_Distance(X, testPt);
  10933. if(i==0 || d1<distBest) {
  10934. distBest = d1;
  10935. R[X_IDX]=testPt[X_IDX];
  10936. R[Y_IDX]=testPt[Y_IDX];
  10937. R[Z_IDX]=testPt[Z_IDX];
  10938. }
  10939. }
  10940. return distBest;
  10941. }
  10942. /* *PolygonHullFace_findClosest */
  10943. static PolygonHullFace *PolygonHullFace_findClosest(PolygonHull *pHull,VectorXYZ X, VectorXYZ R, double *pDist){
  10944. double d1;
  10945. double distBest=1e99;
  10946. PolygonHullFace *pBest=NULL;
  10947. VectorXYZ testPt;
  10948. PolygonHullFace *p;
  10949. HashElem *i;
  10950. /* First pass: Locate the triangle whose center is closest to X.
  10951. ** This will be our first guess of what the closest triangle is.
  10952. ** And because it is probably pretty close to the best, it will make
  10953. ** it easy to eliminate other triangles from contention.
  10954. */
  10955. for(i=readiHashFirst(&pHull->FaceHash); i; i=readiHashNext(i)) {
  10956. p = readiHashData(i);
  10957. d1 = VectorXYZ_DistanceSq(p->center, X);
  10958. if( pBest==0 || d1<distBest ){
  10959. pBest = p;
  10960. distBest = d1;
  10961. }
  10962. }
  10963. if( pBest==0 ){
  10964. return 0;
  10965. }
  10966.  
  10967. /* Compute the exact distance from X to our first guess at the closest
  10968. ** triangle.
  10969. */
  10970. d1=PolygonHull_closestPointOnFace(pBest, X, R);
  10971. distBest = d1*d1;
  10972.  
  10973. /* Do a second pass over the data to see if we can find another
  10974. ** triangle that is closer than pBest. We only need to check
  10975. ** triangle whose center is not further away from X than distBest
  10976. ** plus the triangle radius.
  10977. */
  10978. for(i=readiHashFirst(&pHull->FaceHash); i; i=readiHashNext(i)) {
  10979. p = readiHashData(i);
  10980. if( p==pBest ){
  10981. continue;
  10982. }
  10983. d1 = VectorXYZ_DistanceSq(p->center, X);
  10984. if( d1 - p->radiusSq > distBest ){
  10985. continue;
  10986. }
  10987. d1 = PolygonHull_closestPointOnFace(p, X, testPt);
  10988. if( (d1*d1)<distBest ){
  10989. pBest = p;
  10990. distBest = d1*d1;
  10991. R[X_IDX] = testPt[X_IDX];
  10992. R[Y_IDX] = testPt[Y_IDX];
  10993. R[Z_IDX] = testPt[Z_IDX];
  10994. }
  10995. }
  10996. *pDist = sqrt(distBest);
  10997. return pBest;
  10998. }
  10999. /* *PolygonHullVolume_ById */
  11000. static PolygonHullVolume *PolygonHullVolume_ById(PolygonHull *pHull, int id){
  11001. PolygonHullVolume *pVolume;
  11002. pVolume = readiHashFind(&pHull->VolumeHash, 0, id);
  11003. return pVolume;
  11004. }
  11005. /* *PolygonHullVolume_Create */
  11006. static PolygonHullVolume *PolygonHullVolume_Create(
  11007. PolygonHull *pHull,
  11008. int id
  11009. ){
  11010. PolygonHullVolume *pVolume;
  11011. pVolume = (PolygonHullVolume *)Odie_Alloc( sizeof(PolygonHullVolume) );
  11012. if( pVolume==NULL ) return NULL;
  11013. if(id<0) {
  11014. pHull->VolumeNextId++;
  11015. id=pHull->VolumeNextId;
  11016. } else if (id>=pHull->VolumeNextId) {
  11017. pHull->VolumeNextId=id;
  11018. }
  11019. pVolume->id=id;
  11020. readiHashInsert(&pHull->VolumeHash, 0, id, pVolume);
  11021. return pVolume;
  11022. }
  11023. /* PolygonHullVolume_Unlink */
  11024. static void PolygonHullVolume_Unlink(PolygonHullVolume *pVolume){
  11025. }
  11026. /* PolygonHull_clearSurfaces */
  11027. static void PolygonHull_clearSurfaces(PolygonHull *pHull){
  11028. }
  11029. /* PolygonHull_Reset */
  11030. static void PolygonHull_Reset(PolygonHull *pHull){
  11031. PolygonHull_clearSurfaces(pHull);
  11032. pHull->FaceNextId=0;
  11033. pHull->VertexNextId=0;
  11034. pHull->VolumeNextId=0;
  11035. HashElem *i;
  11036. for(i=readiHashFirst(&pHull->VolumeHash); i; i=readiHashNext(i)) {
  11037. char *ptr=(char *)readiHashData(i);
  11038. Odie_Free((char *)ptr);
  11039. }
  11040. readiHashClear(&pHull->VolumeHash);
  11041. for(i=readiHashFirst(&pHull->FaceHash); i; i=readiHashNext(i)) {
  11042. char *ptr=(char *)readiHashData(i);
  11043. Odie_Free((char *)ptr);
  11044. }
  11045. readiHashClear(&pHull->FaceHash);
  11046. for(i=readiHashFirst(&pHull->VertexHash); i; i=readiHashNext(i)) {
  11047. char *ptr=(char *)readiHashData(i);
  11048. Odie_Free((char *)ptr);
  11049. }
  11050. readiHashClear(&pHull->VertexHash);
  11051. }
  11052. /* PolygonHull_Delete */
  11053. static void PolygonHull_Delete(ClientData clientData){
  11054. PolygonHull *pHull = (PolygonHull *)clientData;
  11055. PolygonHull_Reset(pHull);
  11056. Odie_Free((char *) pHull);
  11057. }
  11058. /* PolygonHull_Clone */
  11059. static int PolygonHull_Clone(
  11060. Tcl_Interp* interp, /* Tcl interpreter for error reporting */
  11061. ClientData metadata, /* Metadata to be cloned */
  11062. ClientData* newMetaData /* Where to put the cloned metadata */
  11063. ){
  11064. Tcl_SetObjResult(interp,
  11065. Tcl_NewStringObj("POLYGONHULLs are not clonable", -1));
  11066. /* For now... */
  11067. return TCL_ERROR;
  11068. }
  11069. /* *Odie_Obj_To_Int */
  11070. Tcl_Obj *Odie_Obj_To_Int(Tcl_Obj *tclObj){
  11071. int sint;
  11072. double s;
  11073. if (Tcl_GetIntFromObj(NULL,tclObj,&sint)==TCL_OK) {
  11074. return tclObj;
  11075. }
  11076. if (Tcl_GetDoubleFromObj(NULL,tclObj,&s)) {
  11077. return tclObj;
  11078. }
  11079. return Tcl_NewIntObj((int)round(s));
  11080. }
  11081. /* Odie_trace_printf */
  11082. void Odie_trace_printf(Tcl_Interp *interp,const char *zFormat, ...){
  11083. /*
  11084. ** Print a trace message
  11085. */
  11086. int n;
  11087. va_list ap;
  11088. char zBuf[4000];
  11089.  
  11090. va_start(ap, zFormat);
  11091. strcpy(zBuf, "puts -nonewline \x7b");
  11092. n = strlen(zBuf);
  11093. vsnprintf(&zBuf[n], sizeof(zBuf)-5-n, zFormat, ap);
  11094. strcat(zBuf, "\x7d\n");
  11095. Tcl_Eval(interp, zBuf);
  11096. }
  11097. /*
  11098. *----------------------------------------------------------------------
  11099. *
  11100. * MergeLists -
  11101. *
  11102. * This procedure combines two sorted lists of SortElement structures
  11103. * into a single sorted list.
  11104. *
  11105. * Results:
  11106. * The unified list of SortElement structures.
  11107. *
  11108. * Side effects:
  11109. * If infoPtr->unique is set then infoPtr->numElements may be updated.
  11110. * Possibly others, if a user-defined comparison command does something
  11111. * weird.
  11112. *
  11113. * Note:
  11114. * If infoPtr->unique is set, the merge assumes that there are no
  11115. * "repeated" elements in each of the left and right lists. In that case,
  11116. * if any element of the left list is equivalent to one in the right list
  11117. * it is omitted from the merged list.
  11118. * This simplified mechanism works because of the special way
  11119. * our MergeSort creates the sublists to be merged and will fail to
  11120. * eliminate all repeats in the general case where they are already
  11121. * present in either the left or right list. A general code would need to
  11122. * skip adjacent initial repeats in the left and right lists before
  11123. * comparing their initial elements, at each step.
  11124. *----------------------------------------------------------------------
  11125. */
  11126.  
  11127. static SortElement *
  11128. MergeLists(
  11129. SortElement *leftPtr, /* First list to be merged; may be NULL. */
  11130. SortElement *rightPtr, /* Second list to be merged; may be NULL. */
  11131. SortInfo *infoPtr) /* Information needed by the comparison
  11132. * operator. */
  11133. {
  11134. SortElement *headPtr, *tailPtr;
  11135. int cmp;
  11136.  
  11137. if (leftPtr == NULL) {
  11138. return rightPtr;
  11139. }
  11140. if (rightPtr == NULL) {
  11141. return leftPtr;
  11142. }
  11143. cmp = SortCompare(leftPtr, rightPtr, infoPtr);
  11144. if (cmp > 0 || (cmp == 0 && infoPtr->unique)) {
  11145. if (cmp == 0) {
  11146. infoPtr->numElements--;
  11147. leftPtr = leftPtr->nextPtr;
  11148. }
  11149. tailPtr = rightPtr;
  11150. rightPtr = rightPtr->nextPtr;
  11151. } else {
  11152. tailPtr = leftPtr;
  11153. leftPtr = leftPtr->nextPtr;
  11154. }
  11155. headPtr = tailPtr;
  11156. if (!infoPtr->unique) {
  11157. while ((leftPtr != NULL) && (rightPtr != NULL)) {
  11158. cmp = SortCompare(leftPtr, rightPtr, infoPtr);
  11159. if (cmp > 0) {
  11160. tailPtr->nextPtr = rightPtr;
  11161. tailPtr = rightPtr;
  11162. rightPtr = rightPtr->nextPtr;
  11163. } else {
  11164. tailPtr->nextPtr = leftPtr;
  11165. tailPtr = leftPtr;
  11166. leftPtr = leftPtr->nextPtr;
  11167. }
  11168. }
  11169. } else {
  11170. while ((leftPtr != NULL) && (rightPtr != NULL)) {
  11171. cmp = SortCompare(leftPtr, rightPtr, infoPtr);
  11172. if (cmp >= 0) {
  11173. if (cmp == 0) {
  11174. infoPtr->numElements--;
  11175. leftPtr = leftPtr->nextPtr;
  11176. }
  11177. tailPtr->nextPtr = rightPtr;
  11178. tailPtr = rightPtr;
  11179. rightPtr = rightPtr->nextPtr;
  11180. } else {
  11181. tailPtr->nextPtr = leftPtr;
  11182. tailPtr = leftPtr;
  11183. leftPtr = leftPtr->nextPtr;
  11184. }
  11185. }
  11186. }
  11187. if (leftPtr != NULL) {
  11188. tailPtr->nextPtr = leftPtr;
  11189. } else {
  11190. tailPtr->nextPtr = rightPtr;
  11191. }
  11192. return headPtr;
  11193. }
  11194.  
  11195. /*
  11196. *----------------------------------------------------------------------
  11197. *
  11198. * SortCompare --
  11199. *
  11200. * This procedure is invoked by MergeLists to determine the proper
  11201. * ordering between two elements.
  11202. *
  11203. * Results:
  11204. * A negative results means the the first element comes before the
  11205. * second, and a positive results means that the second element should
  11206. * come first. A result of zero means the two elements are equal and it
  11207. * doesn't matter which comes first.
  11208. *
  11209. * Side effects:
  11210. * None, unless a user-defined comparison command does something weird.
  11211. *
  11212. *----------------------------------------------------------------------
  11213. */
  11214.  
  11215. static int
  11216. SortCompare(
  11217. SortElement *elemPtr1, SortElement *elemPtr2,
  11218. /* Values to be compared. */
  11219. SortInfo *infoPtr) /* Information passed from the top-level
  11220. * "lsort" command. */
  11221. {
  11222. int order = 0;
  11223.  
  11224. if (infoPtr->sortMode == SORTMODE_ASCII) {
  11225. order = strcmp(elemPtr1->index.strValuePtr,
  11226. elemPtr2->index.strValuePtr);
  11227. } else if (infoPtr->sortMode == SORTMODE_ASCII_NC) {
  11228. order = strcasecmp(elemPtr1->index.strValuePtr,
  11229. elemPtr2->index.strValuePtr);
  11230. } else if (infoPtr->sortMode == SORTMODE_DICTIONARY) {
  11231. order = DictionaryCompare(elemPtr1->index.strValuePtr,
  11232. elemPtr2->index.strValuePtr);
  11233. } else if (infoPtr->sortMode == SORTMODE_INTEGER) {
  11234. long a, b;
  11235.  
  11236. a = elemPtr1->index.intValue;
  11237. b = elemPtr2->index.intValue;
  11238. order = ((a >= b) - (a <= b));
  11239. } else if (infoPtr->sortMode == SORTMODE_REAL) {
  11240. double a, b;
  11241.  
  11242. a = elemPtr1->index.doubleValue;
  11243. b = elemPtr2->index.doubleValue;
  11244. order = ((a >= b) - (a <= b));
  11245. } else {
  11246. Tcl_Obj **objv, *paramObjv[2];
  11247. int objc;
  11248. Tcl_Obj *objPtr1, *objPtr2;
  11249.  
  11250. if (infoPtr->resultCode != TCL_OK) {
  11251. /*
  11252. * Once an error has occurred, skip any future comparisons so as
  11253. * to preserve the error message in sortInterp->result.
  11254. */
  11255.  
  11256. return 0;
  11257. }
  11258.  
  11259.  
  11260. objPtr1 = elemPtr1->index.objValuePtr;
  11261. objPtr2 = elemPtr2->index.objValuePtr;
  11262.  
  11263. paramObjv[0] = objPtr1;
  11264. paramObjv[1] = objPtr2;
  11265.  
  11266. /*
  11267. * We made space in the command list for the two things to compare.
  11268. * Replace them and evaluate the result.
  11269. */
  11270.  
  11271. Tcl_ListObjLength(infoPtr->interp, infoPtr->compareCmdPtr, &objc);
  11272. Tcl_ListObjReplace(infoPtr->interp, infoPtr->compareCmdPtr, objc - 2,
  11273. 2, 2, paramObjv);
  11274. Tcl_ListObjGetElements(infoPtr->interp, infoPtr->compareCmdPtr,
  11275. &objc, &objv);
  11276.  
  11277. infoPtr->resultCode = Tcl_EvalObjv(infoPtr->interp, objc, objv, 0);
  11278.  
  11279. if (infoPtr->resultCode != TCL_OK) {
  11280. Tcl_AddErrorInfo(infoPtr->interp,
  11281. "\n (-compare command)");
  11282. return 0;
  11283. }
  11284.  
  11285. /*
  11286. * Parse the result of the command.
  11287. */
  11288.  
  11289. if (Tcl_GetIntFromObj(infoPtr->interp,
  11290. Tcl_GetObjResult(infoPtr->interp), &order) != TCL_OK) {
  11291. Tcl_ResetResult(infoPtr->interp);
  11292. Tcl_AppendResult(infoPtr->interp,
  11293. "-compare command returned non-integer result", NULL);
  11294. infoPtr->resultCode = TCL_ERROR;
  11295. return 0;
  11296. }
  11297. }
  11298. if (!infoPtr->isIncreasing) {
  11299. order = -order;
  11300. }
  11301. return order;
  11302. }
  11303.  
  11304. /*
  11305. *----------------------------------------------------------------------
  11306. *
  11307. * DictionaryCompare
  11308. *
  11309. * This function compares two strings as if they were being used in an
  11310. * index or card catalog. The case of alphabetic characters is ignored,
  11311. * except to break ties. Thus "B" comes before "b" but after "a". Also,
  11312. * integers embedded in the strings compare in numerical order. In other
  11313. * words, "x10y" comes after "x9y", not * before it as it would when
  11314. * using strcmp().
  11315. *
  11316. * Results:
  11317. * A negative result means that the first element comes before the
  11318. * second, and a positive result means that the second element should
  11319. * come first. A result of zero means the two elements are equal and it
  11320. * doesn't matter which comes first.
  11321. *
  11322. * Side effects:
  11323. * None.
  11324. *
  11325. *----------------------------------------------------------------------
  11326. */
  11327.  
  11328. static int
  11329. DictionaryCompare(
  11330. char *left, char *right) /* The strings to compare. */
  11331. {
  11332. Tcl_UniChar uniLeft, uniRight, uniLeftLower, uniRightLower;
  11333. int diff, zeros;
  11334. int secondaryDiff = 0;
  11335.  
  11336. while (1) {
  11337. if (isdigit(UCHAR(*right)) /* INTL: digit */
  11338. && isdigit(UCHAR(*left))) { /* INTL: digit */
  11339. /*
  11340. * There are decimal numbers embedded in the two strings. Compare
  11341. * them as numbers, rather than strings. If one number has more
  11342. * leading zeros than the other, the number with more leading
  11343. * zeros sorts later, but only as a secondary choice.
  11344. */
  11345.  
  11346. zeros = 0;
  11347. while ((*right == '0') && (isdigit(UCHAR(right[1])))) {
  11348. right++;
  11349. zeros--;
  11350. }
  11351. while ((*left == '0') && (isdigit(UCHAR(left[1])))) {
  11352. left++;
  11353. zeros++;
  11354. }
  11355. if (secondaryDiff == 0) {
  11356. secondaryDiff = zeros;
  11357. }
  11358.  
  11359. /*
  11360. * The code below compares the numbers in the two strings without
  11361. * ever converting them to integers. It does this by first
  11362. * comparing the lengths of the numbers and then comparing the
  11363. * digit values.
  11364. */
  11365.  
  11366. diff = 0;
  11367. while (1) {
  11368. if (diff == 0) {
  11369. diff = UCHAR(*left) - UCHAR(*right);
  11370. }
  11371. right++;
  11372. left++;
  11373. if (!isdigit(UCHAR(*right))) { /* INTL: digit */
  11374. if (isdigit(UCHAR(*left))) { /* INTL: digit */
  11375. return 1;
  11376. } else {
  11377. /*
  11378. * The two numbers have the same length. See if their
  11379. * values are different.
  11380. */
  11381.  
  11382. if (diff != 0) {
  11383. return diff;
  11384. }
  11385. break;
  11386. }
  11387. } else if (!isdigit(UCHAR(*left))) { /* INTL: digit */
  11388. return -1;
  11389. }
  11390. }
  11391. continue;
  11392. }
  11393.  
  11394. /*
  11395. * Convert character to Unicode for comparison purposes. If either
  11396. * string is at the terminating null, do a byte-wise comparison and
  11397. * bail out immediately.
  11398. */
  11399.  
  11400. if ((*left != '\0') && (*right != '\0')) {
  11401. left += Tcl_UtfToUniChar(left, &uniLeft);
  11402. right += Tcl_UtfToUniChar(right, &uniRight);
  11403.  
  11404. /*
  11405. * Convert both chars to lower for the comparison, because
  11406. * dictionary sorts are case insensitve. Covert to lower, not
  11407. * upper, so chars between Z and a will sort before A (where most
  11408. * other interesting punctuations occur).
  11409. */
  11410.  
  11411. uniLeftLower = Tcl_UniCharToLower(uniLeft);
  11412. uniRightLower = Tcl_UniCharToLower(uniRight);
  11413. } else {
  11414. diff = UCHAR(*left) - UCHAR(*right);
  11415. break;
  11416. }
  11417.  
  11418. diff = uniLeftLower - uniRightLower;
  11419. if (diff) {
  11420. return diff;
  11421. }
  11422. if (secondaryDiff == 0) {
  11423. if (Tcl_UniCharIsUpper(uniLeft) && Tcl_UniCharIsLower(uniRight)) {
  11424. secondaryDiff = -1;
  11425. } else if (Tcl_UniCharIsUpper(uniRight)
  11426. && Tcl_UniCharIsLower(uniLeft)) {
  11427. secondaryDiff = 1;
  11428. }
  11429. }
  11430. }
  11431. if (diff == 0) {
  11432. diff = secondaryDiff;
  11433. }
  11434. return diff;
  11435. }
  11436.  
  11437.  
  11438. static int Odie_SortElement_FromObj(
  11439. Tcl_Interp *interp,
  11440. int sortMode,
  11441. Tcl_Obj *valuePtr,
  11442. SortElement *elementPtr
  11443. ) {
  11444. /*
  11445. * Determine the "value" of this object for sorting purposes
  11446. */
  11447. if (sortMode == SORTMODE_ASCII) {
  11448. elementPtr->index.strValuePtr = Tcl_GetString(valuePtr);
  11449. } else if (sortMode == SORTMODE_INTEGER) {
  11450. long a;
  11451.  
  11452. if (Tcl_GetLongFromObj(interp, valuePtr, &a) != TCL_OK) {
  11453. return TCL_ERROR;
  11454. }
  11455. elementPtr->index.intValue = a;
  11456. } else if (sortMode == SORTMODE_REAL) {
  11457. double a;
  11458.  
  11459. if (Tcl_GetDoubleFromObj(interp, valuePtr, &a) != TCL_OK) {
  11460. return TCL_ERROR;
  11461. }
  11462. elementPtr->index.doubleValue = a;
  11463. } else {
  11464. elementPtr->index.objValuePtr = valuePtr;
  11465. }
  11466. elementPtr->objPtr = valuePtr;
  11467. return TCL_OK;
  11468. }
  11469. /* *Odie_MergeList_ToObj */
  11470. static Tcl_Obj *Odie_MergeList_ToObj(SortElement *elementPtr){
  11471. /*
  11472. ** Converts a linked list of structures into
  11473. ** a Tcl list object
  11474. */
  11475. SortElement *loopPtr;
  11476. Tcl_Obj **newArray;
  11477. int i,len=0;
  11478. loopPtr=elementPtr;
  11479. for (len=0; loopPtr != NULL ; loopPtr = loopPtr->nextPtr) {
  11480. len++;
  11481. }
  11482. newArray = (Tcl_Obj **)Odie_Alloc(sizeof(Tcl_Obj *)*len);
  11483. loopPtr=elementPtr;
  11484. for (i=0; loopPtr != NULL ; loopPtr = loopPtr->nextPtr) {
  11485. Tcl_Obj *objPtr = loopPtr->objPtr;
  11486. newArray[i] = objPtr;
  11487. i++;
  11488. //Tcl_IncrRefCount(objPtr);
  11489. }
  11490. return Tcl_NewListObj(len,newArray);
  11491. }
  11492. /* Odie_Lsearch */
  11493. STUB_EXPORT int Odie_Lsearch(int listLength,Tcl_Obj **listObjPtrs,Tcl_Obj *element){
  11494. int i;
  11495. Tcl_Obj *o;
  11496. if(element==NULL) {
  11497. return -1;
  11498. }
  11499.  
  11500. int matchLen;
  11501. char *match=Tcl_GetStringFromObj(element,&matchLen);
  11502.  
  11503. int s2len,found;
  11504. const char *s2;
  11505.  
  11506. if(matchLen < 0) {
  11507. return -1;
  11508. }
  11509.  
  11510. found = 0;
  11511. for(i=0;i<listLength && !found;i++) {
  11512. o=listObjPtrs[i];
  11513. if (o != NULL) {
  11514. s2 = Tcl_GetStringFromObj(o, &s2len);
  11515. } else {
  11516. s2 = "";
  11517. }
  11518. if (matchLen == s2len) {
  11519. found = (strcmp(match, s2) == 0);
  11520. if(found) {
  11521. return i;
  11522. }
  11523. }
  11524. }
  11525. return -1;
  11526. }
  11527. /* *Logicset_To_TclObj */
  11528. STUB_EXPORT Tcl_Obj *Logicset_To_TclObj(Tcl_Obj *set){
  11529. if(set) {
  11530. return Tcl_DuplicateObj(set);
  11531. } else {
  11532. return Tcl_NewObj();
  11533. }
  11534. }
  11535. /* Logicset_LIST_RESET */
  11536. STUB_EXPORT void Logicset_LIST_RESET(Tcl_Obj **set){
  11537. if(*set) {
  11538. Tcl_DecrRefCount(*set);
  11539. }
  11540. *set=Tcl_NewObj();
  11541. }
  11542. /* Logicset_LIST_CONTAINS */
  11543. STUB_EXPORT int Logicset_LIST_CONTAINS(Tcl_Obj **aPtrs,int aLength,Tcl_Obj *element){
  11544. if(element==NULL) return 0;
  11545. if(aLength<1) return 0;
  11546.  
  11547. int matchIdx=Odie_Lsearch(aLength,aPtrs,element);
  11548. if(matchIdx>=0) {
  11549. return 1;
  11550. }
  11551. return 0;
  11552. }
  11553. /* Logicset_Sanitize_List */
  11554. STUB_EXPORT void Logicset_Sanitize_List(char *value,int len){
  11555. int i,skipped=0;
  11556. for(i=0;i<len;i++) {
  11557. unsigned char x=value[i];
  11558. skipped++;
  11559. /* Anything outside this range in non-printable, whitespace, or a delimeter */
  11560. if(x<0x30 || x>0x80 || x==0x7D || x==0x7B) {
  11561. value[i]=0x20;
  11562. continue;
  11563. }
  11564. skipped--;
  11565. }
  11566. }
  11567. /* *Logicset_FromObj */
  11568. STUB_EXPORT Tcl_Obj *Logicset_FromObj(Tcl_Obj *rawlist){
  11569. if(!rawlist) {
  11570. return NULL;
  11571. }
  11572. int len;
  11573. char *rawvalue=Tcl_GetStringFromObj(rawlist,&len);
  11574. if(len==0) {
  11575. return NULL;
  11576. }
  11577. Logicset_Sanitize_List(rawvalue,len);
  11578. Tcl_Obj *tempString=Tcl_NewStringObj(rawvalue,len);
  11579.  
  11580. int listLength,i;
  11581. Tcl_Obj **listObjPtrs;
  11582. if(Tcl_ListObjGetElements(NULL, tempString, &listLength, &listObjPtrs)) {
  11583. Tcl_DecrRefCount(tempString);
  11584. return NULL;
  11585. }
  11586. if(listLength <= 0) {
  11587. Tcl_DecrRefCount(tempString);
  11588. return NULL;
  11589. }
  11590. Tcl_Obj *listObj=Tcl_NewObj();
  11591. for(i=0;i<listLength;i++) {
  11592. Logicset_Add(listObj,listObjPtrs[i]);
  11593. }
  11594. Tcl_DecrRefCount(tempString);
  11595. return listObj;
  11596. }
  11597. /* Logicset_Add */
  11598. STUB_EXPORT int Logicset_Add(Tcl_Obj *aset,Tcl_Obj *element){
  11599. int listLength;
  11600. int i;
  11601. Tcl_Obj **listObjPtrs;
  11602.  
  11603. if(element==NULL) {
  11604. return TCL_OK;
  11605. }
  11606. int matchLen;
  11607. char *match=Tcl_GetStringFromObj(element,&matchLen);
  11608.  
  11609. int s2len;
  11610. const char *s2;
  11611.  
  11612. if(matchLen < 0) {
  11613. return TCL_ERROR;
  11614. }
  11615. if(Tcl_ListObjGetElements(NULL, aset, &listLength, &listObjPtrs)) {
  11616. return TCL_ERROR;
  11617. }
  11618. /* Check that item isn't in list already */
  11619. int found = 0;
  11620. for(i=0;i<listLength && !found;i++) {
  11621. Tcl_Obj *o=listObjPtrs[i];
  11622. if (o != NULL) {
  11623. s2 = Tcl_GetStringFromObj(o, &s2len);
  11624. } else {
  11625. s2 = "";
  11626. }
  11627. if (matchLen == s2len) {
  11628. found = (strcmp(match, s2) == 0);
  11629. if(found) {
  11630. return TCL_OK;
  11631. }
  11632. }
  11633. }
  11634. for(i=0;i<listLength;i++) {
  11635. int cmp = 0;
  11636. Tcl_Obj *o=listObjPtrs[i];
  11637. if (o != NULL) {
  11638. s2 = Tcl_GetStringFromObj(o, &s2len);
  11639. } else {
  11640. s2 = "";
  11641. }
  11642. cmp = strcmp(match, s2);
  11643. if(cmp==0) {
  11644. return TCL_OK;
  11645. } else if (cmp<0) {
  11646. Tcl_Obj *NewVals[1];
  11647. NewVals[0]=element;
  11648. /* Add the new element here */
  11649. return Tcl_ListObjReplace(NULL,aset,i,0,1,NewVals);
  11650. }
  11651. }
  11652. Tcl_ListObjAppendElement(NULL,aset,element);
  11653. return TCL_OK;
  11654. }
  11655. /* Logicset_Include */
  11656. STUB_EXPORT void Logicset_Include(Tcl_Obj *aset,Tcl_Obj *bset){
  11657. /*
  11658. ** Add all elements of A and B together into a new set
  11659. */
  11660. if(!aset || !bset) {
  11661. return;
  11662. }
  11663. int bLength;
  11664. Tcl_Obj **bPtrs;
  11665. if(Tcl_ListObjGetElements(0, bset, &bLength, &bPtrs)) {
  11666. return;
  11667. }
  11668. if(bLength==0) {
  11669. return;
  11670. }
  11671. if(bLength>1) {
  11672. int i;
  11673. for(i=0;i<bLength;i++) {
  11674. Logicset_Include(aset,bPtrs[i]);
  11675. }
  11676. } else {
  11677. if(Logicset_Add(aset,bPtrs[0])) {
  11678. return;
  11679. }
  11680. }
  11681. return;
  11682. }
  11683. /* Logicset_EXPR_AND */
  11684. STUB_EXPORT int Logicset_EXPR_AND(Tcl_Obj *aset,Tcl_Obj *bset){
  11685. /*
  11686. ** Returns 1 if all elements in B are contained in A
  11687. */
  11688. int aLength;
  11689. Tcl_Obj **aPtrs;
  11690. if(!aset || !bset) return 0;
  11691. if(Tcl_ListObjGetElements(0, aset, &aLength, &aPtrs)) {
  11692. return 0;
  11693. }
  11694. int bLength;
  11695. Tcl_Obj **bPtrs;
  11696. if(Tcl_ListObjGetElements(0, bset, &bLength, &bPtrs)) {
  11697. return 0;
  11698. }
  11699. int i;
  11700. for(i=0;i<bLength;i++) {
  11701. int found=Logicset_LIST_CONTAINS(aPtrs,aLength,bPtrs[i]);
  11702. if(!found) {
  11703. return 0;
  11704. }
  11705. }
  11706. return 1;
  11707. }
  11708. /* Logicset_EXPR_OR */
  11709. STUB_EXPORT int Logicset_EXPR_OR(Tcl_Obj *aset,Tcl_Obj *bset){
  11710. int aLength;
  11711. Tcl_Obj **aPtrs;
  11712. if(!aset || !bset) return 0;
  11713. if(Tcl_ListObjGetElements(0, aset, &aLength, &aPtrs)) {
  11714. return 0;
  11715. }
  11716. int bLength;
  11717. Tcl_Obj **bPtrs;
  11718. if(Tcl_ListObjGetElements(0, bset, &bLength, &bPtrs)) {
  11719. return 0;
  11720. }
  11721. int i;
  11722. for(i=0;i<bLength;i++) {
  11723. int found=Logicset_LIST_CONTAINS(aPtrs,aLength,bPtrs[i]);
  11724. if(found) {
  11725. return 1;
  11726. }
  11727. }
  11728. return 0;
  11729. }
  11730. /* *Logicset_PRODUCT_INTERSECT */
  11731. STUB_EXPORT Tcl_Obj *Logicset_PRODUCT_INTERSECT(Tcl_Obj *aset,Tcl_Obj *bset){
  11732. int aLength;
  11733. Tcl_Obj **aPtrs;
  11734. if(!aset) {
  11735. return bset;
  11736. }
  11737. if(!bset) {
  11738. return aset;
  11739. }
  11740. if(Tcl_ListObjGetElements(0, aset, &aLength, &aPtrs)) return bset;
  11741. int bLength;
  11742. Tcl_Obj **bPtrs;
  11743. if(Tcl_ListObjGetElements(0, bset, &bLength, &bPtrs)) return aset;
  11744. int i,resultlen=0;
  11745. Tcl_Obj *result=Tcl_NewObj();
  11746. for(i=0;i<bLength;i++) {
  11747. int found=Logicset_LIST_CONTAINS(aPtrs,aLength,bPtrs[i]);
  11748. if(found) {
  11749. resultlen++;
  11750. Logicset_Add(result,bPtrs[i]);
  11751. }
  11752. }
  11753. if(!resultlen) {
  11754. Tcl_DecrRefCount(result);
  11755. return NULL;
  11756. }
  11757. return result;
  11758. }
  11759. /* *Logicset_PRODUCT_UNION */
  11760. STUB_EXPORT Tcl_Obj *Logicset_PRODUCT_UNION(Tcl_Obj *aset,Tcl_Obj *bset){
  11761. if(!aset) {
  11762. return bset;
  11763. }
  11764. if(!bset) {
  11765. return aset;
  11766. }
  11767. Tcl_Obj *listObj=Tcl_NewObj();
  11768. Logicset_Include(listObj,aset);
  11769. Logicset_Include(listObj,bset);
  11770. return listObj;
  11771. }
  11772. /* *Logicset_PRODUCT_XOR */
  11773. STUB_EXPORT Tcl_Obj *Logicset_PRODUCT_XOR(Tcl_Obj *aset,Tcl_Obj *bset){
  11774. int aLength;
  11775. Tcl_Obj **aPtrs;
  11776. if(!aset) {
  11777. return bset;
  11778. }
  11779. if(!bset) {
  11780. return aset;
  11781. }
  11782. if(Tcl_ListObjGetElements(0, aset, &aLength, &aPtrs)) return bset;
  11783. int bLength;
  11784. Tcl_Obj **bPtrs;
  11785. if(Tcl_ListObjGetElements(0, bset, &bLength, &bPtrs)) return aset;
  11786. int i,resultlen=0;
  11787. Tcl_Obj *result=Tcl_NewObj();
  11788. for(i=0;i<bLength;i++) {
  11789. int found=Logicset_LIST_CONTAINS(aPtrs,aLength,bPtrs[i]);
  11790. if(!found) {
  11791. resultlen++;
  11792. Logicset_Add(result,bPtrs[i]);
  11793. }
  11794. }
  11795. for(i=0;i<aLength;i++) {
  11796. int found=Logicset_LIST_CONTAINS(bPtrs,bLength,aPtrs[i]);
  11797. if(!found) {
  11798. resultlen++;
  11799. Logicset_Add(result,aPtrs[i]);
  11800. }
  11801. }
  11802. if(!resultlen) {
  11803. Tcl_DecrRefCount(result);
  11804. return NULL;
  11805. }
  11806. Tcl_Obj *resultPtr=Odie_ListObj_Sort(result);
  11807. if(resultPtr!=result) {
  11808. Tcl_DecrRefCount(result);
  11809. }
  11810. return resultPtr;
  11811. }
  11812. /* *Logicset_PRODUCT_MISSING */
  11813. STUB_EXPORT Tcl_Obj *Logicset_PRODUCT_MISSING(Tcl_Obj *aset,Tcl_Obj *bset){
  11814. int aLength;
  11815. Tcl_Obj **aPtrs;
  11816. if(!aset) {
  11817. return NULL;
  11818. }
  11819. if(!bset) {
  11820. return aset;
  11821. }
  11822. if(Tcl_ListObjGetElements(0, aset, &aLength, &aPtrs)) return bset;
  11823. int bLength;
  11824. Tcl_Obj **bPtrs;
  11825. if(Tcl_ListObjGetElements(0, bset, &bLength, &bPtrs)) return aset;
  11826. int i,resultlen=0;
  11827. Tcl_Obj *result=Tcl_NewObj();
  11828. for(i=0;i<aLength;i++) {
  11829. int found=Logicset_LIST_CONTAINS(bPtrs,bLength,aPtrs[i]);
  11830. if(!found) {
  11831. resultlen++;
  11832. Logicset_Add(result,aPtrs[i]);
  11833. }
  11834. }
  11835. if(!resultlen) {
  11836. Tcl_DecrRefCount(result);
  11837. return NULL;
  11838. }
  11839. return result;
  11840. }
  11841. /* *Odie_ListObj_Sort */
  11842. STUB_EXPORT Tcl_Obj *Odie_ListObj_Sort(Tcl_Obj *listObj){
  11843. Tcl_Obj *resultPtr=NULL;
  11844. int i, j, length, sortMode;
  11845. int idx;
  11846. Tcl_Obj **listObjPtrs, *indexPtr;
  11847. SortElement *elementArray, *elementPtr;
  11848. SortInfo sortInfo;
  11849.  
  11850. sortInfo.isIncreasing = 1;
  11851. sortInfo.sortMode = SORTMODE_DICTIONARY;
  11852. sortInfo.indexv = NULL;
  11853. sortInfo.unique = 1;
  11854. sortInfo.interp = NULL;
  11855. sortInfo.resultCode = TCL_OK;
  11856.  
  11857. /*
  11858. * The subList array below holds pointers to temporary lists built during
  11859. * the merge sort. Element i of the array holds a list of length 2**i.
  11860. */
  11861. # define NUM_LISTS 30
  11862. SortElement *subList[NUM_LISTS+1];
  11863.  
  11864.  
  11865. sortInfo.resultCode = Tcl_ListObjGetElements(sortInfo.interp, listObj,
  11866. &length, &listObjPtrs);
  11867.  
  11868. if(length<2) {
  11869. /*
  11870. ** If the list is zero length, just return
  11871. ** the original pointer
  11872. */
  11873. return listObj;
  11874. }
  11875.  
  11876. if (sortInfo.resultCode != TCL_OK || length <= 0) {
  11877. goto done;
  11878. }
  11879.  
  11880. sortInfo.numElements = length;
  11881.  
  11882. sortMode = sortInfo.sortMode;
  11883. if ((sortMode == SORTMODE_ASCII_NC)
  11884. || (sortMode == SORTMODE_DICTIONARY)) {
  11885. /*
  11886. * For this function's purpose all string-based modes are equivalent
  11887. */
  11888. sortMode = SORTMODE_ASCII;
  11889. }
  11890.  
  11891. /*
  11892. * Initialize the sublists. After the following loop, subList[i] will
  11893. * contain a sorted sublist of length 2**i. Use one extra subList at the
  11894. * end, always at NULL, to indicate the end of the lists.
  11895. */
  11896.  
  11897. for (j=0 ; j<=NUM_LISTS ; j++) {
  11898. subList[j] = NULL;
  11899. }
  11900.  
  11901. /*
  11902. * The following loop creates a SortElement for each list element and
  11903. * begins sorting it into the sublists as it appears.
  11904. */
  11905.  
  11906. elementArray = (SortElement *) Odie_Alloc( length * sizeof(SortElement));
  11907.  
  11908. for (i=0; i < length; i++){
  11909. idx = i;
  11910. indexPtr = listObjPtrs[idx];
  11911. sortInfo.resultCode=Odie_SortElement_FromObj(sortInfo.interp,sortMode,indexPtr,&elementArray[i]);
  11912. if(sortInfo.resultCode!=TCL_OK) {
  11913. goto done1;
  11914. }
  11915. }
  11916.  
  11917. for (i=0; i < length; i++){
  11918. /*
  11919. * Merge this element in the pre-existing sublists (and merge together
  11920. * sublists when we have two of the same size).
  11921. */
  11922.  
  11923. elementArray[i].nextPtr = NULL;
  11924. elementPtr = &elementArray[i];
  11925. for (j=0 ; subList[j] ; j++) {
  11926. elementPtr = MergeLists(subList[j], elementPtr, &sortInfo);
  11927. subList[j] = NULL;
  11928. }
  11929. if (j >= NUM_LISTS) {
  11930. j = NUM_LISTS-1;
  11931. }
  11932. subList[j] = elementPtr;
  11933. }
  11934.  
  11935. /*
  11936. * Merge all sublists
  11937. */
  11938.  
  11939. elementPtr = subList[0];
  11940. for (j=1 ; j<NUM_LISTS ; j++) {
  11941. elementPtr = MergeLists(subList[j], elementPtr, &sortInfo);
  11942. }
  11943.  
  11944. /*
  11945. * Now store the sorted elements in the result list.
  11946. */
  11947.  
  11948. if (sortInfo.resultCode == TCL_OK) {
  11949. resultPtr=Odie_MergeList_ToObj(elementPtr);
  11950.  
  11951. }
  11952.  
  11953. done1:
  11954. Odie_Free((char *) elementArray);
  11955.  
  11956. done:
  11957. if (sortInfo.sortMode == SORTMODE_COMMAND) {
  11958. Tcl_DecrRefCount(sortInfo.compareCmdPtr);
  11959. Tcl_DecrRefCount(listObj);
  11960. sortInfo.compareCmdPtr = NULL;
  11961. }
  11962. if (sortInfo.resultCode != TCL_OK) {
  11963. return NULL;
  11964. }
  11965. return resultPtr;
  11966. }
  11967. /* Odie_Trace */
  11968. int Odie_Trace(int newvalue){
  11969. OdieTrace=newvalue;
  11970. return OdieTrace;
  11971. }
  11972. /* *Odie_LiteralConstantObj */
  11973. Tcl_Obj *Odie_LiteralConstantObj(int which){
  11974. if(which > ODIE_STATIC_MAX || which < 0) {
  11975. Tcl_IncrRefCount(OdieStatic[ODIE_STATIC_NULL]);
  11976. return OdieStatic[ODIE_STATIC_NULL];
  11977. }
  11978. Tcl_IncrRefCount(OdieStatic[which]);
  11979. return OdieStatic[which];
  11980. }
  11981. /* *Odie_StoreObj */
  11982. Tcl_Obj *Odie_StoreObj(Tcl_Obj *value){
  11983. Tcl_Obj *storedVal;
  11984. double floatVal;
  11985. int intVal,strLen;
  11986. char *stringVal,*strtmp;
  11987. if(!value) {
  11988. storedVal=OdieStatic[ODIE_STATIC_NULL];
  11989. Tcl_IncrRefCount(storedVal);
  11990. nOdieDictSpecNull++;
  11991. return storedVal;
  11992. }
  11993. /* If this value is already shared, just store it and bump the refcount */
  11994. if(Tcl_IsShared(value)) {
  11995. Tcl_IncrRefCount(value);
  11996. nOdieDictSpecRecycled++;
  11997. return value;
  11998. }
  11999. /* Try to map this string to an existing literal */
  12000. stringVal=Tcl_GetString(value);
  12001. storedVal=Odie_constant(stringVal,0);
  12002. if(storedVal) {
  12003. Tcl_IncrRefCount(storedVal);
  12004. nOdieDictSpecShared++;
  12005. return storedVal;
  12006. }
  12007. /* Avoid storing a list or other volitile data */
  12008. strtmp=strchr(stringVal,' ');
  12009. if(!strtmp) {
  12010. strtmp=strchr(stringVal,'/');
  12011. if(!strtmp) {
  12012. storedVal=Odie_constant(stringVal,1);
  12013. Tcl_IncrRefCount(storedVal);
  12014. return storedVal;
  12015. }
  12016. }
  12017. Tcl_IncrRefCount(value);
  12018. return value;
  12019. }
  12020. /* *Odie_constant */
  12021. static Tcl_Obj *Odie_constant(const char *zName,int create){
  12022. int len,isNew=0;
  12023. Tcl_HashEntry *pEntry;
  12024. Tcl_Obj *p;
  12025. if(zName==NULL) {
  12026. return NULL;
  12027. }
  12028. if(create) {
  12029. pEntry=Tcl_CreateHashEntry(&OdieLiteralStringTable,zName,&isNew);
  12030. } else {
  12031. pEntry=Tcl_FindHashEntry(&OdieLiteralStringTable,zName);
  12032. }
  12033. if(isNew) {
  12034. nOdieObjString++;
  12035. len = strlen(zName);
  12036. p=Tcl_NewStringObj(zName,len);
  12037. Tcl_IncrRefCount(p);
  12038. Tcl_SetHashValue(pEntry,(ClientData)p);
  12039. return p;
  12040. }
  12041. if(pEntry) {
  12042. p=(Tcl_Obj*)Tcl_GetHashValue(pEntry);
  12043. return p;
  12044. }
  12045. return NULL;
  12046. }
  12047. /* Odie_SameString */
  12048. int Odie_SameString(char *aPtr,char *bPtr){
  12049. if(aPtr==bPtr) {
  12050. return 1;
  12051. }
  12052. if(!bPtr || !aPtr) {
  12053. return 0;
  12054. }
  12055. if(strcmp(aPtr,bPtr)==0) {
  12056. return 1;
  12057. }
  12058. return 0;
  12059. }
  12060. /* *Odie_LiteralString */
  12061. char *Odie_LiteralString(const char *zName){
  12062. Tcl_Obj *p;
  12063. p=Odie_constant(zName,1);
  12064. return Tcl_GetString(p);
  12065. }
  12066. /* *Odie_LiteralStringObj */
  12067. Tcl_Obj *Odie_LiteralStringObj(const char *zName){
  12068. Tcl_Obj *p;
  12069. p=Odie_constant(zName,1);
  12070. Tcl_IncrRefCount(p);
  12071. return p;
  12072. }
  12073. /* Odie_DictObjPut */
  12074. inline extern int Odie_DictObjPut(Tcl_Interp *interp,Tcl_Obj *pDictObj,const char *pField,Tcl_Obj *pValue){
  12075. int result=TCL_OK;
  12076. if(!pValue) {
  12077. return TCL_OK;
  12078. }
  12079. result=Tcl_DictObjPut(interp,pDictObj,Odie_LiteralStringObj(pField),pValue);
  12080. return result;
  12081. }
  12082. /* *Odie_HashGet */
  12083. Tcl_Obj *Odie_HashGet(Tcl_HashTable *localDict,char *fieldStr){
  12084. Tcl_Obj *valuePtr;
  12085. Tcl_HashEntry *i;
  12086. if(!localDict) {
  12087. return NULL;
  12088. }
  12089. i=Tcl_FindHashEntry(localDict,fieldStr);
  12090. if(!i) {
  12091. return NULL;
  12092. }
  12093. valuePtr=(Tcl_Obj*)Tcl_GetHashValue(i);
  12094. if(!valuePtr) {
  12095. return NULL;
  12096. }
  12097. nOdieDictSpecAccessed++;
  12098. Tcl_IncrRefCount(valuePtr);
  12099. return valuePtr;
  12100. }
  12101. /* Odie_HashPut */
  12102. void Odie_HashPut(Tcl_HashTable **infoDictPtr,const char *key,Tcl_Obj *value){
  12103. Tcl_HashTable *result=*infoDictPtr;
  12104. Tcl_HashEntry *pEntry;
  12105. Tcl_Obj *valuePtr;
  12106. int isNew=0;
  12107. int delete=0,len=0;
  12108. char *valueStr;
  12109. if(value==NULL) {
  12110. delete=1;
  12111. }
  12112. valueStr=Tcl_GetString(value);
  12113. len=strlen(valueStr);
  12114. if(len==0) {
  12115. delete=1;
  12116. }
  12117.  
  12118. if(!result && delete) {
  12119. return;
  12120. }
  12121. if(!result) {
  12122. result=(Tcl_HashTable*)Odie_Alloc( sizeof(Tcl_HashTable) );
  12123. Tcl_InitHashTable(result,TCL_STRING_KEYS);
  12124. nOdieHashTable++;
  12125. nOdieHashTableCreated++;
  12126. *infoDictPtr=result;
  12127. }
  12128. if(delete) {
  12129. /* If we were given a null or an empty string, delete */
  12130. pEntry=Tcl_FindHashEntry(result,key);
  12131. if(!pEntry) return;
  12132. nOdieDictSpecDeleted++;
  12133. nOdieDictSpecCount--;
  12134. valuePtr=(Tcl_Obj*)Tcl_GetHashValue(pEntry);
  12135. Tcl_DecrRefCount(valuePtr);
  12136. Tcl_DeleteHashEntry(pEntry);
  12137. return;
  12138. }
  12139. pEntry=Tcl_CreateHashEntry(result,Odie_LiteralString(key),&isNew);
  12140. if(!isNew) {
  12141. valuePtr=(Tcl_Obj*)Tcl_GetHashValue(pEntry);
  12142. nOdieDictSpecModified++;
  12143. Tcl_DecrRefCount(valuePtr);
  12144. } else {
  12145. nOdieDictSpecCreated++;
  12146. nOdieDictSpecCount++;
  12147. }
  12148. valuePtr=Odie_StoreObj(value);
  12149. Tcl_SetHashValue(pEntry,valuePtr);
  12150. return;
  12151. }
  12152. /* Odie_HashFree */
  12153. void Odie_HashFree(Tcl_HashTable **infoDictPtr){
  12154. if(*infoDictPtr) {
  12155. Tcl_HashSearch searchPtr;
  12156. Tcl_HashEntry *i;
  12157. Tcl_HashTable *ptr=*infoDictPtr;
  12158. for(i=Tcl_FirstHashEntry(ptr,&searchPtr); i ; i = Tcl_NextHashEntry(&searchPtr)) {
  12159. Tcl_Obj *valuePtr=(Tcl_Obj *)Tcl_GetHashValue(i);
  12160. Tcl_DecrRefCount(valuePtr);
  12161. nOdieDictSpecCount--;
  12162. nOdieDictSpecDeleted++;
  12163. }
  12164. nOdieHashTableDeleted++;
  12165. nOdieHashTable--;
  12166. Tcl_DeleteHashTable(ptr);
  12167. Tcl_Free((char*)ptr);
  12168. }
  12169. *infoDictPtr=NULL;
  12170. }
  12171. /* Odie_constant_inject */
  12172. static void Odie_constant_inject(Tcl_Obj *value){
  12173. int len,isNew=0;
  12174. char *zName=Tcl_GetString(value);
  12175. Tcl_HashEntry *pEntry;
  12176. pEntry=Tcl_CreateHashEntry(&OdieLiteralStringTable,zName,&isNew);
  12177. if(isNew) {
  12178. nOdieObjString++;
  12179. Tcl_IncrRefCount(value);
  12180. Tcl_SetHashValue(pEntry,(ClientData)value);
  12181. }
  12182. }
  12183. /* Odie_RoidFromString */
  12184. Roid Odie_RoidFromString(char *idstring,short charcode){
  12185. char prefix[32];
  12186. int id;
  12187. int result;
  12188.  
  12189. if(!idstring) {
  12190. return -1;
  12191. }
  12192. result=sscanf(idstring,"%d",&id);
  12193. if(result>0) {
  12194. return id;
  12195. }
  12196. result=sscanf(idstring,"%c%d",prefix,&id);
  12197. if(result>0) {
  12198. return id;
  12199. }
  12200. return -1;
  12201. }
  12202. /* *Irm_NewLocationObj */
  12203. Tcl_Obj *Irm_NewLocationObj(Irm_Location *loc){
  12204. Tcl_Obj *pResult = Tcl_NewObj();
  12205. Tcl_ListObjAppendElement(NULL, pResult, Odie_LiteralIntObj(loc->deckid));
  12206. Tcl_ListObjAppendElement(NULL, pResult, Tcl_NewIntObj(loc->x));
  12207. Tcl_ListObjAppendElement(NULL, pResult, Tcl_NewIntObj(loc->y));
  12208. return pResult;
  12209. }
  12210. /* Location_FromName */
  12211. int Location_FromName(char *stringVal,int *did,double *x,double *y,double *z){
  12212. /*
  12213. ** Obtain location from name
  12214. */
  12215. #ifdef build_IRM
  12216. int deckid=0;
  12217. char type=0;
  12218. int roid;
  12219. int found=0;
  12220. int result=sscanf(stringVal,"%c%d-%d",&type,&roid,&deckid);
  12221. #endif
  12222. Irm_Location temp;
  12223. temp.deckid=0;
  12224. temp.x=0;
  12225. temp.y=0;
  12226. #ifdef build_IRM
  12227. if(result==2 || result==3) {
  12228. switch(type) {
  12229. case 'c': {
  12230. if(CrewRoute_ComptCenter(roid,deckid,&temp)) {
  12231. if(deckid) {
  12232. temp.deckid=deckid;
  12233. } else {
  12234. temp.deckid=1;
  12235. }
  12236. temp.x=0;
  12237. temp.y=0;
  12238. }
  12239. found=1;
  12240. break;
  12241. }
  12242. case 'e': {
  12243. SimNode *pDest=SimNode_ById(roid,0);
  12244. if(pDest) {
  12245. SimNode_StructLocation(&temp,pDest);
  12246. found=1;
  12247. }
  12248. break;
  12249. }
  12250. case 'p': {
  12251. Portal *pDest=Portal_ById(roid,0);
  12252. if(pDest) {
  12253. Portal_StructLocation(&temp,pDest);
  12254. found=1;
  12255. }
  12256. break;
  12257. }
  12258. case 'v': {
  12259. Crew *pDest=Crew_ById(roid,0);
  12260. if(pDest) {
  12261. Crew_StructLocation(&temp,pDest);
  12262. found=1;
  12263. }
  12264. break;
  12265. }
  12266. }
  12267. }
  12268. if (!found) {
  12269. Entity *pDest=Entity_ByName(stringVal,0);
  12270. if(!pDest) {
  12271. return TCL_ERROR;
  12272. }
  12273. Entity_StructLocation(&temp,pDest);
  12274. }
  12275. #else
  12276. Entity *pDest=Entity_ByName(stringVal,0);
  12277. if(!pDest) {
  12278. return TCL_ERROR;
  12279. }
  12280. Entity_StructLocation(&temp,pDest);
  12281. #endif
  12282. *did=temp.deckid;
  12283. *x=temp.x;
  12284. *y=temp.y;
  12285. *z=temp.zoff;
  12286. return TCL_OK;
  12287. }
  12288. /* Location_FromTclObj */
  12289. int Location_FromTclObj(Tcl_Interp *interp, Tcl_Obj *pList,int *did,double *x,double *y){
  12290. int listlen;
  12291. Tcl_Obj **elist;
  12292. double z;
  12293. if(Tcl_ListObjGetElements(interp,pList,&listlen,&elist)) {
  12294. return TCL_ERROR;
  12295. }
  12296. if(listlen == 1) {
  12297. /*
  12298. ** Obtain location from name
  12299. */
  12300. char *stringVal=Tcl_GetString(pList);
  12301. if (Location_FromName(stringVal,did,x,y,&z)) {
  12302. Tcl_AppendResult(interp, "Unknown entity ", stringVal, 0);
  12303. return TCL_ERROR;
  12304. }
  12305. return TCL_OK;
  12306. }
  12307. if(listlen < 3 || listlen > 4) {
  12308. Tcl_AppendResult(interp, "Could not interpret location ", Tcl_GetString(pList), 0);
  12309. return TCL_ERROR;
  12310. }
  12311. if( Tcl_GetIntFromObj(interp, elist[0], did) ) return TCL_ERROR;
  12312. if( Tcl_GetDoubleFromObj(interp, elist[1], x) ) return TCL_ERROR;
  12313. if( Tcl_GetDoubleFromObj(interp, elist[2], y) ) return TCL_ERROR;
  12314. return TCL_OK;
  12315. }
  12316. /* Location_Base_FromTclObj */
  12317. int Location_Base_FromTclObj(Tcl_Interp *interp, Tcl_Obj *pList,int *did,double *x,double *y,double *z){
  12318. int listlen;
  12319. Tcl_Obj **elist;
  12320.  
  12321. if(Tcl_ListObjGetElements(interp,pList,&listlen,&elist)) {
  12322. return TCL_ERROR;
  12323. }
  12324. if(listlen == 1) {
  12325. /*
  12326. ** Obtain location from name
  12327. */
  12328. char *stringVal=Tcl_GetString(pList);
  12329. if (Location_FromName(stringVal,did,x,y,z)) {
  12330. Tcl_AppendResult(interp, "Unknown entity ", stringVal, 0);
  12331. return TCL_ERROR;
  12332. }
  12333. return TCL_OK;
  12334. }
  12335. if(listlen < 3 || listlen > 4) {
  12336. Tcl_AppendResult(interp, "Could not interpret location ", Tcl_GetString(pList), 0);
  12337. return TCL_ERROR;
  12338. }
  12339. if( Tcl_GetIntFromObj(interp, elist[0], did) ) return TCL_ERROR;
  12340. if( Tcl_GetDoubleFromObj(interp, elist[1], x) ) return TCL_ERROR;
  12341. if( Tcl_GetDoubleFromObj(interp, elist[2], y) ) return TCL_ERROR;
  12342. *z=0.0;
  12343. if(listlen==4) {
  12344. if( Tcl_GetDoubleFromObj(interp, elist[3], z) ) return TCL_ERROR;
  12345. }
  12346. return TCL_OK;
  12347. }
  12348. /* location_match */
  12349. int location_match(Irm_Location *a,Irm_Location *b,int tolerance){
  12350. /*
  12351. ** Returns a 0 if the two points are "close enough"
  12352. */
  12353. int d;
  12354. if(a==b) {
  12355. return 1;
  12356. }
  12357. if(a->deckid!=b->deckid) {
  12358. return 0;
  12359. }
  12360. d=a->x - b->x;
  12361. if(d<-tolerance||d>tolerance) {
  12362. return 0;
  12363. }
  12364. d=a->y - b->y;
  12365. if(d<-tolerance||d>tolerance) {
  12366. return 0;
  12367. }
  12368. return 1;
  12369. }
  12370. /* irm_gridhash_decompose */
  12371. void irm_gridhash_decompose(Tcl_WideInt gridhash,int *style,int *rdeckid,int *rgx,int *rgy){
  12372. Tcl_WideInt mask;
  12373. int gy,gx,deckid;
  12374. int isHex=0;
  12375.  
  12376. /* Unpack the coordinates */
  12377. mask=gridhash;
  12378. gx=mask & 0xFFFF;
  12379. if(gx & 0x8000) {
  12380. /* Restore negative */
  12381. gx-=0xffff;
  12382. gx--;
  12383. }
  12384.  
  12385. mask>>=16;
  12386. gy=mask & 0xFFF;
  12387. if(gy & 0x800) {
  12388. /* Restore negative */
  12389. gy-=0xfff;
  12390. gy--;
  12391. }
  12392.  
  12393. mask>>=12;
  12394. deckid=mask & 0x3F;
  12395.  
  12396. mask>>=6;
  12397. isHex=mask;
  12398.  
  12399. *style=isHex;
  12400. *rdeckid=deckid;
  12401. *rgx=gx;
  12402. *rgy=gy;
  12403. }
  12404. /* irm_gridhash_compose */
  12405. Tcl_WideInt irm_gridhash_compose (int style,int deckid,int gx,int gy){
  12406. Tcl_WideInt result;
  12407. result=(style&1);
  12408. result<<=6;
  12409. /* Encode the coordinate packed into a 32 bit integer */
  12410. result|=(0x3F & deckid);
  12411. result<<=12;
  12412. result|=(0xFFF & gy);
  12413. result<<=16;
  12414. result|=(0xFFFF & gx);
  12415. return result;
  12416. }
  12417. /* irm_squaregrid_hash */
  12418. Tcl_WideInt irm_squaregrid_hash(int grid,int deckid,int x,int y){
  12419. int gx,gy;
  12420. gy=(int)round(y/grid);
  12421. gx=(int)round(x/grid);
  12422.  
  12423. return irm_gridhash_compose(0,deckid,gx,gy);
  12424. }
  12425. /* irm_hexgrid_hash */
  12426. Tcl_WideInt irm_hexgrid_hash(int grid,int deckid,int x,int y){
  12427. int gx,gy;
  12428.  
  12429. gy=(int)round(y/grid);
  12430. if(abs(gy)%2==1){
  12431. gx=(int)round((x-grid/2)/grid);
  12432. } else {
  12433. gx=(int)round(x/grid);
  12434. }
  12435. return irm_gridhash_compose(1,deckid,gx,gy);
  12436. }
  12437. /* irm_gridhash_location */
  12438. void irm_gridhash_location(Irm_Location *lPtr,Tcl_WideInt gridhash,int gridsize){
  12439. int gy,gx,deckid;
  12440. int isHex=0;
  12441. irm_gridhash_decompose(gridhash,&isHex,&deckid,&gx,&gy);
  12442.  
  12443. lPtr->deckid=deckid;
  12444. lPtr->y=gy*gridsize;
  12445. if(isHex) {
  12446. if(abs(gy)%2==1) {
  12447. lPtr->x=gx*gridsize+(gridsize/2);
  12448. } else {
  12449. lPtr->x=gx*gridsize;
  12450. }
  12451. } else {
  12452. lPtr->x=gx*gridsize;
  12453. }
  12454. }
  12455. /* Simulator_Init */
  12456. void Simulator_Init(Simulator *p){}
  12457. /* Simulator_Reset */
  12458. void Simulator_Reset(Simulator *p){}
  12459. /* Structure Entity */
  12460.  
  12461. const struct OdieParamNameMap Entity_paramNameMap[] = {
  12462. { "active", CSTRUCT_ENTITY_ACTIVE, PTYPE_INT },
  12463. { "changed", CSTRUCT_ENTITY_CHANGED, PTYPE_INT },
  12464. { "class", CSTRUCT_ENTITY_CLASS, PTYPE_FLOAT },
  12465. { "drawn", CSTRUCT_ENTITY_DRAWN, PTYPE_INT },
  12466. { "groupid", CSTRUCT_ENTITY_GROUPID, PTYPE_INT },
  12467. { "hidden", CSTRUCT_ENTITY_HIDDEN, PTYPE_INT },
  12468. { "highlight", CSTRUCT_ENTITY_HIGHLIGHT, PTYPE_INT },
  12469. { "is_type", CSTRUCT_ENTITY_IS_TYPE, PTYPE_INT },
  12470. { "moved", CSTRUCT_ENTITY_MOVED, PTYPE_INT },
  12471. { "nchild", CSTRUCT_ENTITY_NCHILD, PTYPE_INT },
  12472. { "oncount", CSTRUCT_ENTITY_ONCOUNT, PTYPE_INT },
  12473. { "open", CSTRUCT_ENTITY_OPEN, PTYPE_INT },
  12474. { "parent", CSTRUCT_ENTITY_PARENT, PTYPE_INT },
  12475. { "redraw", CSTRUCT_ENTITY_REDRAW, PTYPE_INT },
  12476. { "repaint", CSTRUCT_ENTITY_REPAINT, PTYPE_INT },
  12477. { "synthetic", CSTRUCT_ENTITY_SYNTHETIC, PTYPE_INT },
  12478. { "trace", CSTRUCT_ENTITY_TRACE, PTYPE_INT },
  12479. { "visible", CSTRUCT_ENTITY_VISIBLE, PTYPE_INT },
  12480. };
  12481. const struct OdieParamNameMap Entity_canonicalNameMap[] = {
  12482. { "active", CSTRUCT_ENTITY_ACTIVE, PTYPE_INT },
  12483. { "changed", CSTRUCT_ENTITY_CHANGED, PTYPE_INT },
  12484. { "class", CSTRUCT_ENTITY_CLASS, PTYPE_FLOAT },
  12485. { "drawn", CSTRUCT_ENTITY_DRAWN, PTYPE_INT },
  12486. { "groupid", CSTRUCT_ENTITY_GROUPID, PTYPE_INT },
  12487. { "hidden", CSTRUCT_ENTITY_HIDDEN, PTYPE_INT },
  12488. { "highlight", CSTRUCT_ENTITY_HIGHLIGHT, PTYPE_INT },
  12489. { "is_type", CSTRUCT_ENTITY_IS_TYPE, PTYPE_INT },
  12490. { "moved", CSTRUCT_ENTITY_MOVED, PTYPE_INT },
  12491. { "nchild", CSTRUCT_ENTITY_NCHILD, PTYPE_INT },
  12492. { "oncount", CSTRUCT_ENTITY_ONCOUNT, PTYPE_INT },
  12493. { "open", CSTRUCT_ENTITY_OPEN, PTYPE_INT },
  12494. { "parent", CSTRUCT_ENTITY_PARENT, PTYPE_INT },
  12495. { "redraw", CSTRUCT_ENTITY_REDRAW, PTYPE_INT },
  12496. { "repaint", CSTRUCT_ENTITY_REPAINT, PTYPE_INT },
  12497. { "synthetic", CSTRUCT_ENTITY_SYNTHETIC, PTYPE_INT },
  12498. { "trace", CSTRUCT_ENTITY_TRACE, PTYPE_INT },
  12499. { "visible", CSTRUCT_ENTITY_VISIBLE, PTYPE_INT },
  12500. };
  12501.  
  12502.  
  12503. #include <math.h>
  12504. #include <string.h>
  12505.  
  12506. #define ENTITY_SEARCH_NCOUNT 15
  12507.  
  12508. static const char *ENTITY_SEARCH_strs[] = {
  12509. "active",
  12510. "class",
  12511. "comptid",
  12512. "deckid",
  12513. "drawn",
  12514. "groupid",
  12515. "hidden",
  12516. "highlight",
  12517. "moved",
  12518. "redraw",
  12519. "repaint",
  12520. "synthetic",
  12521. "trace",
  12522. "typeid",
  12523. "visible",
  12524. 0
  12525. };
  12526. enum ENTITY_SEARCH_enum {
  12527. ENTITY_SEARCH_ACTIVE,
  12528. ENTITY_SEARCH_CLASS,
  12529. ENTITY_SEARCH_COMPTID,
  12530. ENTITY_SEARCH_DECKID,
  12531. ENTITY_SEARCH_DRAWN,
  12532. ENTITY_SEARCH_GROUPID,
  12533. ENTITY_SEARCH_HIDDEN,
  12534. ENTITY_SEARCH_HIGHLIGHT,
  12535. ENTITY_SEARCH_MOVED,
  12536. ENTITY_SEARCH_REDRAW,
  12537. ENTITY_SEARCH_REPAINT,
  12538. ENTITY_SEARCH_SYNTHETIC,
  12539. ENTITY_SEARCH_TRACE,
  12540. ENTITY_SEARCH_TYPEID,
  12541. ENTITY_SEARCH_VISIBLE
  12542. };
  12543. /* SimType_Walk_Parent */
  12544. int SimType_Walk_Parent(Entity *p){
  12545. /*
  12546. ** Subroutine to decend into children of a simtype
  12547. */
  12548. Entity *parent;
  12549. if(!p) {
  12550. return 0;
  12551. }
  12552. if(p->public_hidden) {
  12553. return -1;
  12554. }
  12555. if(p->public_active==2) {
  12556. return -1;
  12557. }
  12558. if(p->public_active==1) {
  12559. return 1;
  12560. }
  12561. if(p->public_visible) {
  12562. return 1;
  12563. }
  12564. if(p->public_parent) {
  12565. parent=SimType_ById(p->public_parent,0);
  12566. if(parent) {
  12567. return SimType_Walk_Parent(parent);
  12568. }
  12569. }
  12570. return 0;
  12571. }
  12572. /* *Entity_ById */
  12573. Entity *Entity_ById(char prefix,Roid id,int createFlag){
  12574. Entity *p;
  12575. char zName[32];
  12576. sprintf(zName, "%c%d", prefix, id);
  12577. p=Entity_ByName(zName,createFlag);
  12578. if(createFlag) {
  12579. if(!p->id) {
  12580. p->id=id;
  12581. }
  12582. }
  12583. return p;
  12584. }
  12585. /* *Entity_ByName */
  12586. Entity *Entity_ByName(const char *zName,int createFlag){
  12587. Tcl_HashEntry *pEntry;
  12588.  
  12589. assert( zName!=0 );
  12590. if(CurrentSim->GlobalSim) {
  12591. pEntry=Tcl_FindHashEntry(&CurrentSim->GlobalSim->EntityIdSet,zName);
  12592. } else {
  12593. pEntry=Tcl_FindHashEntry(&CurrentSim->EntityIdSet,zName);
  12594. }
  12595. if(pEntry) {
  12596. return (Entity*)Tcl_GetHashValue(pEntry);
  12597. }
  12598. if(createFlag) {
  12599. return EntityCreate(zName);
  12600. }
  12601. return NULL;
  12602. }
  12603. /* *Entity_ExportField */
  12604. Tcl_Obj *Entity_ExportField(Entity *e,Tcl_HashTable *local,char *field,int nullcode){
  12605. Tcl_Obj *result=Entity_GetField(e,local,field);
  12606.  
  12607. if(result) {
  12608. return result;
  12609. }
  12610. if(nullcode==ODIE_NULL_ZERO) {
  12611. return Tcl_NewBooleanObj(0);
  12612. }
  12613. if(nullcode==ODIE_NULL_EMPTY) {
  12614. return Tcl_NewObj();
  12615. }
  12616. return NULL;
  12617. }
  12618. /* *Entity_First */
  12619. Tcl_HashEntry *Entity_First(Simulator *sim,Tcl_HashSearch *search){
  12620. if(sim->GlobalSim) {
  12621. return Tcl_FirstHashEntry(&sim->GlobalSim->EntityIdSet,search);
  12622. } else {
  12623. return Tcl_FirstHashEntry(&sim->EntityIdSet,search);
  12624. }
  12625. }
  12626. /* *Entity_GetDict */
  12627. Tcl_Obj *Entity_GetDict(Entity *e,Tcl_HashTable *local){
  12628. Tcl_HashTable *localDict=NULL;
  12629. Tcl_Obj *pResult=NULL;
  12630. Entity *p=NULL;
  12631. Entity *pStack[10];
  12632. int i,count=-1;
  12633.  
  12634. p=e;
  12635. while(p && count<10) {
  12636. count++;
  12637. pStack[count]=p;
  12638. p=p->pType;
  12639. }
  12640. /*
  12641. ** Add the minimum specs for the class
  12642. */
  12643. for(i=count;i>=0;i--) {
  12644. p=pStack[i];
  12645. localDict=p->infoDict;
  12646. if(localDict) {
  12647. Tcl_HashSearch searchPtr;
  12648. Tcl_HashEntry *i;
  12649. for(i=Tcl_FirstHashEntry(localDict,&searchPtr); i ; i = Tcl_NextHashEntry(&searchPtr)) {
  12650. if(!pResult) pResult=Tcl_NewDictObj();
  12651. Odie_DictObjPut(0,pResult,Tcl_GetHashKey(localDict,i),Tcl_GetHashValue(i));
  12652. }
  12653. }
  12654. }
  12655. localDict=local;
  12656. if(localDict) {
  12657. Tcl_HashSearch searchPtr;
  12658. Tcl_HashEntry *i;
  12659. for(i=Tcl_FirstHashEntry(localDict,&searchPtr); i ; i = Tcl_NextHashEntry(&searchPtr)) {
  12660. if(!pResult) pResult=Tcl_NewDictObj();
  12661. Odie_DictObjPut(0,pResult,Tcl_GetHashKey(localDict,i),Tcl_GetHashValue(i));
  12662. }
  12663. }
  12664. return pResult;
  12665. }
  12666. /* *Entity_GetField */
  12667. Tcl_Obj *Entity_GetField(Entity *e,Tcl_HashTable *local,char *field){
  12668. Tcl_Obj *result=NULL;
  12669. Entity *p=NULL;
  12670.  
  12671. result=Odie_HashGet(local,field);
  12672. if(result) {
  12673. return result;
  12674. }
  12675. p=e;
  12676. while(p) {
  12677. result=Odie_HashGet(p->infoDict,field);
  12678. if(result) {
  12679. return result;
  12680. }
  12681. if(p) p=p->pType;
  12682. }
  12683. return NULL;
  12684. }
  12685. /* *Entity_GroupToTclObj */
  12686. Tcl_Obj *Entity_GroupToTclObj(Entity *pNode){
  12687. Roid groupid;
  12688. if(!pNode) {
  12689. return Tcl_NewBooleanObj(0);
  12690. }
  12691. groupid=Entity_StructGetGroup(pNode);
  12692. if(!groupid) {
  12693. return Tcl_NewBooleanObj(0);
  12694. }
  12695. return Irm_NewRoidObj(groupid);
  12696. }
  12697. /* *Entity_Identify */
  12698. Tcl_Obj *Entity_Identify(Entity *pNode){
  12699. if(!pNode) {
  12700. return Tcl_NewObj();
  12701. }
  12702. if(pNode->public_is_type) {
  12703. return Irm_NewRoidObj(pNode->id);
  12704. }
  12705. if(pNode->name!=NULL) {
  12706. return Odie_LiteralStringObj(pNode->name);
  12707. } else {
  12708. return Irm_NewRoidObj(pNode->id);
  12709. }
  12710. }
  12711. /* *Entity_IdentifyCompartment */
  12712. Entity *Entity_IdentifyCompartment(Tcl_Obj *entryPtr){
  12713. Entity *comptPtr=NULL;
  12714. int intval;
  12715. if(entryPtr==NULL) {
  12716. return NULL;
  12717. }
  12718. if(Tcl_GetIntFromObj(NULL,entryPtr,&intval)==TCL_OK) {
  12719. if(intval<=0) {
  12720. return NULL;
  12721. }
  12722. comptPtr=Entity_ById('c',intval,0);
  12723. } else {
  12724. comptPtr=Entity_ByName(Tcl_GetString(entryPtr),0);
  12725. }
  12726. return comptPtr;
  12727. }
  12728. /* *Entity_PublicId */
  12729. Tcl_Obj *Entity_PublicId(Entity *pNode){
  12730. char idstring[64];
  12731. if(!pNode) {
  12732. return Irm_NewRoidObj(0);
  12733. }
  12734. if(pNode->pType) {
  12735. if(pNode->pType->name!=NULL) {
  12736. return Odie_LiteralStringObj(pNode->pType->name);
  12737. }
  12738. }
  12739. sprintf(idstring,"%d",pNode->id);
  12740. return Odie_LiteralStringObj(idstring);
  12741. }
  12742. /* *Entity_SpecHashGet */
  12743. Tcl_Obj *Entity_SpecHashGet(Entity *p,Tcl_Obj* key,int nulltype){
  12744. return Entity_ExportField(p->pType,p->infoDict,Tcl_GetString(key),nulltype);
  12745. }
  12746. /* *Entity_StructGet */
  12747. Tcl_Obj *Entity_StructGet(Entity *pNode,int field){
  12748. switch (field) {
  12749. case CSTRUCT_ENTITY_HIDDEN: return Odie_LiteralIntObj(pNode->public_hidden);
  12750. case CSTRUCT_ENTITY_IS_TYPE: return Odie_LiteralIntObj(pNode->public_is_type);
  12751. case CSTRUCT_ENTITY_REDRAW: return Odie_LiteralIntObj(pNode->public_redraw);
  12752. case CSTRUCT_ENTITY_ACTIVE: return Odie_LiteralIntObj(pNode->public_active);
  12753. case CSTRUCT_ENTITY_GROUPID: return Irm_NewRoidObj(pNode->public_groupid);
  12754. case CSTRUCT_ENTITY_TRACE: return Odie_LiteralIntObj(pNode->public_trace);
  12755. case CSTRUCT_ENTITY_REPAINT: return Odie_LiteralIntObj(pNode->public_repaint);
  12756. case CSTRUCT_ENTITY_VISIBLE: return Odie_LiteralIntObj(pNode->public_visible);
  12757. case CSTRUCT_ENTITY_MOVED: return Odie_LiteralIntObj(pNode->public_moved);
  12758. case CSTRUCT_ENTITY_CHANGED: return Odie_LiteralIntObj(pNode->public_changed);
  12759. case CSTRUCT_ENTITY_OPEN: return Odie_LiteralIntObj(pNode->public_open);
  12760. case CSTRUCT_ENTITY_CLASS: {
  12761. char zBuf[2];
  12762. zBuf[0]=pNode->public_class;
  12763. zBuf[1]=0;
  12764. return Odie_LiteralStringObj(zBuf);
  12765. }
  12766.  
  12767. case CSTRUCT_ENTITY_PARENT: return Irm_NewRoidObj(pNode->public_parent);
  12768. case CSTRUCT_ENTITY_SYNTHETIC: return Odie_LiteralIntObj(pNode->public_synthetic);
  12769. case CSTRUCT_ENTITY_HIGHLIGHT: return Odie_LiteralIntObj(pNode->public_highlight);
  12770. case CSTRUCT_ENTITY_DRAWN: return Odie_LiteralIntObj(pNode->public_drawn);
  12771. case CSTRUCT_ENTITY_NCHILD: return Odie_LiteralIntObj(pNode->public_nchild);
  12772. case CSTRUCT_ENTITY_ONCOUNT: return Odie_LiteralIntObj(pNode->public_oncount);
  12773. }
  12774. return NULL;
  12775. }
  12776. /* *Entity_StructGetType */
  12777. Entity *Entity_StructGetType(Entity *p){
  12778. return p->pType;
  12779. }
  12780. /* *Entity_StructToDict */
  12781. Tcl_Obj *Entity_StructToDict(Tcl_Interp *interp,Entity *p,int virtual){
  12782. Tcl_Obj *pResult=NULL;
  12783. int i;
  12784. if(virtual) {
  12785. pResult=Entity_GetDict(p->pType,p->infoDict);
  12786. }
  12787. if(!pResult) {
  12788. pResult=Tcl_NewObj();
  12789. }
  12790. /* Finaly, Add the Tcl Data */
  12791. for(i=0;i<CSTRUCT_ENTITY_Count;i++) {
  12792. Tcl_Obj *newElement=Entity_StructGet(p,i);
  12793. Odie_DictObjPut(interp,pResult,Entity_paramNameMap[i].zName,newElement);
  12794. }
  12795. if(virtual) {
  12796. Entity_StructAddLocation(interp,p,pResult);
  12797. }
  12798. return pResult;
  12799. }
  12800. /* *Entity_StructTypeIdToTclObj */
  12801. Tcl_Obj *Entity_StructTypeIdToTclObj(Entity *pNode){
  12802. if(!pNode) {
  12803. return Irm_NewRoidObj(0);
  12804. }
  12805. if(!pNode->pType) {
  12806. return Irm_NewRoidObj(0);
  12807. }
  12808. return Irm_NewRoidObj(pNode->pType->id);
  12809. }
  12810. /* *Entity_TypeToTclObj */
  12811. Tcl_Obj *Entity_TypeToTclObj(Entity *pNode){
  12812. Entity *pType;
  12813. if(!pNode) {
  12814. return Tcl_NewBooleanObj(0);
  12815. }
  12816. pType=Entity_StructGetType(pNode);
  12817. if(!pType) {
  12818. return Tcl_NewBooleanObj(0);
  12819. }
  12820. return Irm_NewRoidObj(pType->id);
  12821. }
  12822. /* *EntityCreate */
  12823. Entity *EntityCreate(const char *zName){
  12824. int len,isNew;
  12825. Tcl_HashEntry *pEntry;
  12826. Entity *p;
  12827. if(CurrentSim->GlobalSim) {
  12828. pEntry = Tcl_CreateHashEntry(&CurrentSim->GlobalSim->EntityIdSet, zName, &isNew);
  12829. } else {
  12830. pEntry = Tcl_CreateHashEntry(&CurrentSim->EntityIdSet, zName, &isNew);
  12831. }
  12832. if(isNew) {
  12833. len = strlen(zName);
  12834. p = (Entity *)Odie_Alloc( sizeof(*p)+len+1 );
  12835. strcpy(p->name, zName);
  12836. p->public_class=zName[0];
  12837. Entity_StructAlloc(p);
  12838. Tcl_SetHashValue(pEntry,(ClientData)p);
  12839. return p;
  12840. }
  12841. if(pEntry) {
  12842. p=(Entity *)Tcl_GetHashValue(pEntry);
  12843. return p;
  12844. }
  12845. return NULL;
  12846. }
  12847. /* Entity_ApplySettings */
  12848. void Entity_ApplySettings(Entity *pNode){
  12849. if(pNode->public_class=='e') {
  12850. Tcl_Obj *comptidObj=Entity_GetField(NULL,pNode->infoDict,"comptid");
  12851. if(comptidObj) {
  12852. /*
  12853. ** If a local spec for "comptid" is given, use that
  12854. ** as an implied "comptdid" statement
  12855. */
  12856. pNode->comptPtr=Entity_IdentifyCompartment(comptidObj);
  12857. }
  12858. }
  12859. }
  12860. /* Entity_BuildMatch */
  12861. int Entity_BuildMatch(Tcl_Interp *interp,Tcl_Obj *matchvar,int *matchStruct){
  12862. int llength,idx;
  12863.  
  12864. /*
  12865. ** Default to universal match
  12866. */
  12867. for(idx=0;idx<ENTITY_SEARCH_NCOUNT;idx++) {
  12868. matchStruct[idx]=-1;
  12869. }
  12870. /* Handle a null */
  12871. if(!matchvar) {
  12872. return TCL_OK;
  12873. }
  12874.  
  12875. if( Tcl_ListObjLength(interp, matchvar, &llength) ) return TCL_ERROR;
  12876. if( llength%2!=0 ){
  12877. Tcl_AppendResult(interp, "Search params must be a key/value list "
  12878. "valid keys: visible hidden class redraw highlighted", 0);
  12879. return TCL_ERROR;
  12880. }
  12881.  
  12882. for(idx=0; idx<llength-1; idx+=2){
  12883. int field;
  12884. int value;
  12885. Tcl_Obj *pObj;
  12886.  
  12887. Tcl_ListObjIndex(0, matchvar, idx, &pObj);
  12888. if( Tcl_GetIndexFromObj(interp, pObj, ENTITY_SEARCH_strs, "option", 0, &field) ){
  12889. return TCL_ERROR;
  12890. }
  12891. Tcl_ListObjIndex(0, matchvar, idx+1, &pObj);
  12892. if(field==ENTITY_SEARCH_CLASS) {
  12893. char *str,prefix;
  12894. str=Tcl_GetString(pObj);
  12895. if(str) {
  12896. prefix=str[0];
  12897. matchStruct[field]=prefix;
  12898. }
  12899. } else {
  12900. if(Tcl_GetIntFromObj(interp, pObj, &value)) {
  12901. return TCL_ERROR;
  12902. }
  12903. matchStruct[field]=value;
  12904. }
  12905. }
  12906. return TCL_OK;
  12907. }
  12908. /* Entity_Delete */
  12909. void Entity_Delete(Entity *p){
  12910. Entity_StructFree(p);
  12911. Odie_Free((char *)p);
  12912. }
  12913. /* Entity_FromTclObj */
  12914. int Entity_FromTclObj(Tcl_Interp *interp, Tcl_Obj *pObj, Entity **ppEntity){
  12915. *ppEntity = NULL;
  12916. int i;
  12917. if( Tcl_GetIntFromObj(interp, pObj, &i) == TCL_OK ) {
  12918. *ppEntity = SimType_ById(i, 0);
  12919. if(*ppEntity) {
  12920. return TCL_OK;
  12921. }
  12922. }
  12923. Tcl_ResetResult(interp);
  12924. *ppEntity = Entity_ByName(Tcl_GetString(pObj),0);
  12925.  
  12926. if( *ppEntity==0 ){
  12927. Tcl_AppendResult(interp, "no such entity: ",
  12928. Tcl_GetString(pObj), 0);
  12929. return TCL_ERROR;
  12930. }
  12931. return TCL_OK;
  12932. }
  12933. /* Entity_Module_Advance */
  12934. void Entity_Module_Advance(Simulator *ActiveSim,int clocktime){
  12935. /* Default empty implementation */
  12936. }
  12937. /* Entity_Module_Free */
  12938. void Entity_Module_Free(Simulator *sim){
  12939. Tcl_HashSearch searchPtr;
  12940. Tcl_HashEntry *i;
  12941.  
  12942. if(!sim->module_entity) return;
  12943. for(i=Entity_First(sim,&searchPtr); i ; i = Tcl_NextHashEntry(&searchPtr)) {
  12944. Entity *p = (Entity*)Tcl_GetHashValue(i);
  12945. Entity_StructFree(p);
  12946. Odie_Free((char *)p);
  12947. }
  12948. for(i=SimType_First(sim,&searchPtr); i ; i = Tcl_NextHashEntry(&searchPtr)) {
  12949. Entity *p = (Entity*)Tcl_GetHashValue(i);
  12950. Entity_StructFree(p);
  12951. Odie_Free((char *)p);
  12952. }
  12953. Tcl_DeleteHashTable(&sim->EntityIdSet);
  12954. Tcl_DeleteHashTable(&sim->SimTypeIdSet);
  12955. sim->module_entity=0;
  12956. }
  12957. /* Entity_Module_Init */
  12958. void Entity_Module_Init(Simulator *sim){}
  12959. /* Entity_Module_Rewind */
  12960. void Entity_Module_Rewind(Simulator *sim){
  12961. Tcl_HashSearch searchPtr;
  12962. Tcl_HashEntry *i;
  12963.  
  12964. if(!sim->module_entity) return;
  12965. for(i=Entity_First(sim,&searchPtr); i ; i = Tcl_NextHashEntry(&searchPtr)) {
  12966. Entity *p = (Entity*)Tcl_GetHashValue(i);
  12967. p->public_redraw=1;
  12968. p->public_repaint=1;
  12969. }
  12970. }
  12971. /* Entity_Node_ApplyLocation */
  12972. void Entity_Node_ApplyLocation(Entity *pNode){
  12973. #ifdef build_IRM
  12974. Entity *comptPtr;
  12975. int cid,sid,c;
  12976. c=CrewrouteSubcompartmentAt(pNode->x,pNode->y,pNode->deckid,&sid,&cid,NULL,NULL);
  12977. comptPtr=Entity_ById('c',c,0);
  12978. pNode->public_moved=1;
  12979. if(comptPtr) {
  12980. pNode->comptPtr=comptPtr;
  12981. } else {
  12982. pNode->comptPtr=NULL;
  12983. }
  12984. #endif
  12985. }
  12986. /* Entity_Node_GetLink */
  12987. void Entity_Node_GetLink(Tcl_Obj *pResult,Entity *pNode,char *linktype){}
  12988. /* Entity_nodeeval */
  12989. int Entity_nodeeval(Tcl_Interp *interp,Entity *p,Tcl_Obj *body,int writeback){
  12990. Tcl_Obj *id;
  12991. int i,len;
  12992. Tcl_Obj *varv[CSTRUCT_ENTITY_Count*2];
  12993. int result;
  12994.  
  12995. Entity_StructWith(interp,p,1,varv);
  12996. id=Entity_Identify(p);
  12997. Tcl_ObjSetVar2(interp,Odie_LiteralStringObj("id"),NULL,id,0);
  12998. Tcl_ObjSetVar2(interp,Odie_LiteralStringObj("typeid"),NULL,Entity_TypeToTclObj(p),0);
  12999. Tcl_ObjSetVar2(interp,Odie_LiteralStringObj("groupid"),NULL,Entity_GroupToTclObj(p),0);
  13000. /*
  13001. for(i=0;i<CSTRUCT_ENTITY_Count*2;i++) {
  13002. Tcl_IncrRefCount(varv[i]);
  13003. }
  13004. */
  13005. result=Tcl_EvalObjEx(interp, body, 0);
  13006.  
  13007. if(result!=TCL_OK) {
  13008. return result;
  13009. }
  13010. if(writeback){
  13011. /*
  13012. ** Read values back into the dict
  13013. ** For now, we limit writeback to state variables
  13014. ** And we don't care about garbage values
  13015. */
  13016. int changed=0;
  13017. for(i=0;i<CSTRUCT_ENTITY_Count*2;i+=2) {
  13018. Tcl_Obj *newValue;
  13019. int offset;
  13020. int type;
  13021. newValue=Tcl_ObjGetVar2(interp,varv[i],(Tcl_Obj*)NULL,0);
  13022. if(newValue==varv[i+1]) {
  13023. /* Undocumented, unsanctioned, but it works in practice
  13024. ** If the pointer hasn't changed, neither has the value
  13025. */
  13026. continue;
  13027. }
  13028. if(!newValue) {
  13029. /* Variable must have been unset... move along */
  13030. continue;
  13031. }
  13032. if( Entity_StructValueOffset(0, varv[i], &offset, &type) == TCL_OK ) {
  13033. Entity_StructSet(interp,p,offset,newValue);
  13034. changed++;
  13035. }
  13036. }
  13037. if(changed) {
  13038. Entity_ApplySettings(p);
  13039. }
  13040. }
  13041. /*
  13042. for(i=0;i<CSTRUCT_ENTITY_Count*2;i++) {
  13043. Tcl_DecrRefCount(varv[i]);
  13044. }
  13045. */
  13046. return TCL_OK;
  13047. }
  13048. /* Entity_Rewind */
  13049. void Entity_Rewind(Entity *p, int revert){}
  13050. /* Entity_SetFromObj */
  13051. int Entity_SetFromObj(Tcl_Interp *interp,Entity *pType, Tcl_Obj *field, Tcl_Obj *value){
  13052. /* Manipulate the DICT representation */
  13053. int err,type,offset=-1;
  13054. /* Reset any cached group pointer */
  13055. pType->gType=NULL;
  13056. if( Entity_StructValueOffset(interp, field, &offset, &type) == TCL_OK ) {
  13057. err=Entity_StructSet(interp,pType->pType,offset,value);
  13058. if(err==TCL_OK) {
  13059. Entity_ApplySettings(pType->pType);
  13060. }
  13061. return err;
  13062. }
  13063. Odie_HashPut(&pType->infoDict,Tcl_GetString(field),value);
  13064. return TCL_OK;
  13065. }
  13066. /* Entity_SpecHashClear */
  13067. void Entity_SpecHashClear(Entity *p){
  13068. Odie_HashFree(&p->infoDict);
  13069. }
  13070. /* Entity_SpecHashPut */
  13071. void Entity_SpecHashPut(Entity *p,Tcl_Obj *key,Tcl_Obj *value){
  13072. Odie_HashPut(&p->infoDict,Tcl_GetString(key),value);
  13073. }
  13074. /* Entity_StructAddLocation */
  13075. void Entity_StructAddLocation(Tcl_Interp *interp,Entity *p, Tcl_Obj *pValueDict){
  13076. Tcl_Obj *tempval;
  13077. #ifdef build_IRM
  13078. if(p->public_class=='k') {
  13079. /* Always provide a path if not given
  13080. ** And only trust the local dict
  13081. */
  13082. Tcl_Obj *pathobj=Entity_ExportField(NULL,p->infoDict,"path",ODIE_NULL_EMPTY);
  13083. Odie_DictObjPut(0,pValueDict,"path",pathobj);
  13084. } else {
  13085. if(p->attached_to) {
  13086. switch (p->attached_type) {
  13087. case CSTRUCT_crew: {
  13088. return Crew_StructAddLocation(interp,p->attached_to,pValueDict);
  13089. }
  13090. case CSTRUCT_entity: {
  13091. return Entity_StructAddLocation(interp,p->attached_to,pValueDict);
  13092. }
  13093. case CSTRUCT_portal: {
  13094. return Portal_StructAddLocation(interp,p->attached_to,pValueDict);
  13095. }
  13096. case CSTRUCT_simnode: {
  13097. return SimNode_StructAddLocation(interp,p->attached_to,pValueDict);
  13098. }
  13099. }
  13100. }
  13101. Odie_DictObjPut(0,pValueDict,"deckid",Odie_LiteralIntObj(p->deckid));
  13102. if(p->deckid) {
  13103. tempval=Tcl_NewObj();
  13104. Tcl_ListObjAppendElement(interp, tempval, Odie_LiteralIntObj(p->deckid));
  13105. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->x));
  13106. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->y));
  13107. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->zoff));
  13108. Odie_DictObjPut(interp,pValueDict,"center",tempval);
  13109. }
  13110. tempval=Tcl_NewObj();
  13111. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->nx));
  13112. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->ny));
  13113. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->nz));
  13114. Odie_DictObjPut(0,pValueDict,"orientation",tempval);
  13115. if(p->comptPtr) {
  13116. Odie_DictObjPut(0,pValueDict,"compartment",Entity_Identify(p->comptPtr));
  13117. }
  13118. }
  13119. #else
  13120. Odie_DictObjPut(0,pValueDict,"deckid",Odie_LiteralIntObj(p->deckid));
  13121. if(p->deckid) {
  13122. tempval=Tcl_NewObj();
  13123. Tcl_ListObjAppendElement(interp, tempval, Odie_LiteralIntObj(p->deckid));
  13124. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->x));
  13125. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->y));
  13126. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->zoff));
  13127. Odie_DictObjPut(interp,pValueDict,"center",tempval);
  13128. }
  13129. tempval=Tcl_NewObj();
  13130. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->nx));
  13131. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->ny));
  13132. Tcl_ListObjAppendElement(interp, tempval, Tcl_NewIntObj(p->nz));
  13133. Odie_DictObjPut(0,pValueDict,"orientation",tempval);
  13134. if(p->comptPtr) {
  13135. Odie_DictObjPut(0,pValueDict,"compartment",Entity_Identify(p->comptPtr));
  13136. }
  13137. #endif
  13138. }
  13139. /* Entity_StructAlloc */
  13140. void Entity_StructAlloc(Entity *p){}
  13141. /* Entity_StructAttachLocation */
  13142. int Entity_StructAttachLocation(Tcl_Interp *interp,Entity *pNat,Tcl_Obj *nodeName){
  13143. char type=0;
  13144. int roid;
  13145. char *stringVal=Tcl_GetString(nodeName);
  13146. int result=sscanf(stringVal,"%c%d",&type,&roid);
  13147.  
  13148. if(result!=2) {
  13149. pNat->attached_type=0;
  13150. pNat->attached_to=NULL;
  13151. return TCL_OK;
  13152. }
  13153. #ifdef build_IRM
  13154. switch(type) {
  13155. case 'c': {
  13156. Compartment *pDest;
  13157. if(Compartment_FromTclObj(interp,nodeName,&pDest)) return TCL_ERROR;
  13158. pNat->attached_type=CSTRUCT_compartment;
  13159. pNat->attached_to=pDest;
  13160. return TCL_OK;
  13161. }
  13162. case 'e': {
  13163. SimNode *pDest;
  13164. if(SimNode_FromTclObj(interp,nodeName,&pDest)) return TCL_ERROR;
  13165. pNat->attached_type=CSTRUCT_simnode;
  13166. pNat->attached_to=pDest;
  13167. return TCL_OK;
  13168. }
  13169. case 'p': {
  13170. Portal *pDest;
  13171. if(Portal_FromTclObj(interp,nodeName,&pDest)) return TCL_ERROR;
  13172. pNat->attached_type=CSTRUCT_portal;
  13173. pNat->attached_to=pDest;
  13174. return TCL_OK;
  13175. }
  13176. case 'v': {
  13177. Crew *pDest;
  13178. if(Crew_FromTclObj(interp,nodeName,&pDest)) return TCL_ERROR;
  13179. pNat->attached_type=CSTRUCT_crew;
  13180. pNat->attached_to=pDest;
  13181. return TCL_OK;
  13182. }
  13183. default: {
  13184. Entity *pDest;
  13185. if(Entity_FromTclObj(interp,nodeName,&pDest)) {
  13186. return TCL_ERROR;
  13187. }
  13188. pNat->attached_type=CSTRUCT_entity;
  13189. pNat->attached_to=pDest;
  13190. return TCL_OK;
  13191. }
  13192. }
  13193. return TCL_ERROR;
  13194. #else
  13195. Entity *pDest;
  13196. if(Entity_FromTclObj(interp,nodeName,&pDest)) {
  13197. return TCL_ERROR;
  13198. }
  13199. pNat->attached_type=CSTRUCT_entity;
  13200. pNat->attached_to=pDest;
  13201. return TCL_OK;
  13202. #endif
  13203. }
  13204. /* Entity_StructChanged */
  13205. int Entity_StructChanged(Entity *p){ return 0; }
  13206. /* Entity_StructFree */
  13207. void Entity_StructFree(Entity *p){
  13208. Odie_HashFree(&p->infoDict);
  13209. p->infoDict=NULL;
  13210. }
  13211. /* Entity_StructFree_Private */
  13212. void Entity_StructFree_Private(Entity *p){}
  13213. /* Entity_StructGetGroup */
  13214. Roid Entity_StructGetGroup(Entity *p){
  13215. Roid groupid=-1;
  13216. if(p->public_groupid>0) {
  13217. return p->public_groupid;
  13218. }
  13219.  
  13220. if(p->pType) {
  13221. groupid=SimType_StructGetGroup(p->pType);
  13222. if(groupid>0) {
  13223. return groupid;
  13224. }
  13225. }
  13226. /*
  13227. ** Nodes defaults to the compartment they are within
  13228. ** If no group is given through the type or adopted type
  13229. */
  13230. if(p->comptPtr) {
  13231. groupid=Entity_StructGetGroup(p->comptPtr);
  13232. if(groupid>0) {
  13233. return groupid;
  13234. }
  13235. }
  13236. return 0;
  13237. }
  13238. /* Entity_StructLocation */
  13239. void Entity_StructLocation (Irm_Location *lstruct,Entity *p){
  13240. #ifdef build_IRM
  13241. if(p->attached_to) {
  13242. switch (p->attached_type) {
  13243. case CSTRUCT_crew: {
  13244. return Crew_StructLocation(lstruct,p->attached_to);
  13245. }
  13246. case CSTRUCT_entity: {
  13247. return Entity_StructLocation(lstruct,p->attached_to);
  13248. }
  13249. case CSTRUCT_portal: {
  13250. return Portal_StructLocation(lstruct,p->attached_to);
  13251. }
  13252. case CSTRUCT_simnode: {
  13253. return SimNode_StructLocation(lstruct,p->attached_to);
  13254. }
  13255. }
  13256. }
  13257. #endif
  13258. lstruct->deckid=p->deckid;
  13259. lstruct->x=p->x;
  13260. lstruct->y=p->y;
  13261. lstruct->zoff=p->zoff;
  13262. }
  13263. /* Entity_StructMatches */
  13264. int Entity_StructMatches(Entity *p,int *matchSearch){
  13265.  
  13266. if(matchSearch[ENTITY_SEARCH_CLASS]>=0) {
  13267. if(matchSearch[ENTITY_SEARCH_CLASS]!=(int)p->public_class) return 0;
  13268. }
  13269. if(matchSearch[ENTITY_SEARCH_DECKID]>=0) {
  13270. if(matchSearch[ENTITY_SEARCH_DECKID]!=(int)p->deckid) return 0;
  13271. }
  13272. if(matchSearch[ENTITY_SEARCH_DRAWN]>=0) {
  13273. if(matchSearch[ENTITY_SEARCH_DRAWN]!=(int)p->public_drawn) return 0;
  13274. }
  13275.  
  13276. if(matchSearch[ENTITY_SEARCH_COMPTID]>=0) {
  13277. Entity *gPtr=p->comptPtr;
  13278. if(!gPtr) {
  13279. return 0;
  13280. } else {
  13281. if(gPtr->id != matchSearch[ENTITY_SEARCH_COMPTID]) {
  13282. return 0;
  13283. }
  13284. }
  13285. }
  13286.  
  13287. if(matchSearch[ENTITY_SEARCH_GROUPID]>=0) {
  13288. Roid groupid=Entity_StructGetGroup(p);
  13289. if(groupid != matchSearch[ENTITY_SEARCH_GROUPID]) {
  13290. return 0;
  13291. }
  13292. }
  13293.  
  13294. if(matchSearch[ENTITY_SEARCH_HIDDEN]>=0) {
  13295. if(matchSearch[ENTITY_SEARCH_HIDDEN]!=p->public_hidden) return 0;
  13296. }
  13297. if(matchSearch[ENTITY_SEARCH_ACTIVE]>=0) {
  13298. if(matchSearch[ENTITY_SEARCH_ACTIVE]!=p->public_active) return 0;
  13299. }
  13300. if(matchSearch[ENTITY_SEARCH_HIGHLIGHT]>=0) {
  13301. if(matchSearch[ENTITY_SEARCH_HIGHLIGHT]!=p->public_highlight) return 0;
  13302. }
  13303. if(matchSearch[ENTITY_SEARCH_MOVED]>=0) {
  13304. if(matchSearch[ENTITY_SEARCH_MOVED]!=p->public_moved) return 0;
  13305. }
  13306. if(matchSearch[ENTITY_SEARCH_REDRAW]>=0) {
  13307. if(matchSearch[ENTITY_SEARCH_REDRAW]!=p->public_redraw) return 0;
  13308. }
  13309.  
  13310. if(matchSearch[ENTITY_SEARCH_REPAINT]>=0) {
  13311. if(matchSearch[ENTITY_SEARCH_REPAINT]!=p->public_repaint) return 0;
  13312. }
  13313. if(matchSearch[ENTITY_SEARCH_SYNTHETIC]>=0) {
  13314. if(matchSearch[ENTITY_SEARCH_SYNTHETIC]!=p->public_synthetic) return 0;
  13315. }
  13316.  
  13317. if(matchSearch[ENTITY_SEARCH_TYPEID]>=0) {
  13318. if(!p->pType) {
  13319. return 0;
  13320. } else {
  13321. if(p->pType->id != matchSearch[ENTITY_SEARCH_TYPEID]) {
  13322. return 0;
  13323. }
  13324. }
  13325. }
  13326. if(matchSearch[ENTITY_SEARCH_TRACE]>=0) {
  13327. if(matchSearch[ENTITY_SEARCH_TRACE]!=p->public_trace) return 0;
  13328. }
  13329. if(matchSearch[ENTITY_SEARCH_VISIBLE]>=0) {
  13330. if(matchSearch[ENTITY_SEARCH_VISIBLE]!=p->public_visible) return 0;
  13331. }
  13332. return 1;
  13333. }
  13334. /* Entity_StructSet */
  13335. int Entity_StructSet(Tcl_Interp *interp,Entity *pNode,int field,Tcl_Obj *value){
  13336.  
  13337. if(field < 0 ) {
  13338. return TCL_ERROR;
  13339. }
  13340.  
  13341. switch (field) {
  13342. case CSTRUCT_ENTITY_HIDDEN: {
  13343. int intValue;
  13344. double floatValue;
  13345. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13346. Tcl_ResetResult(interp);
  13347. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13348. intValue=(int)floatValue;
  13349. }
  13350. pNode->public_hidden=intValue;
  13351. return TCL_OK;
  13352. }
  13353. case CSTRUCT_ENTITY_IS_TYPE: {
  13354. int intValue;
  13355. double floatValue;
  13356. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13357. Tcl_ResetResult(interp);
  13358. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13359. intValue=(int)floatValue;
  13360. }
  13361. pNode->public_is_type=intValue;
  13362. return TCL_OK;
  13363. }
  13364. case CSTRUCT_ENTITY_REDRAW: {
  13365. int intValue;
  13366. double floatValue;
  13367. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13368. Tcl_ResetResult(interp);
  13369. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13370. intValue=(int)floatValue;
  13371. }
  13372. pNode->public_redraw=intValue;
  13373. return TCL_OK;
  13374. }
  13375. case CSTRUCT_ENTITY_ACTIVE: {
  13376. int intValue;
  13377. double floatValue;
  13378. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13379. Tcl_ResetResult(interp);
  13380. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13381. intValue=(int)floatValue;
  13382. }
  13383. pNode->public_active=intValue;
  13384. return TCL_OK;
  13385. }
  13386. case CSTRUCT_ENTITY_GROUPID: {
  13387. Roid roidValue;
  13388. if(Irm_GetRoidFromObj(interp,value,&roidValue)) return TCL_ERROR;
  13389. pNode->public_groupid=(Roid)roidValue;
  13390. return TCL_OK;
  13391. }
  13392. case CSTRUCT_ENTITY_TRACE: {
  13393. int intValue;
  13394. double floatValue;
  13395. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13396. Tcl_ResetResult(interp);
  13397. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13398. intValue=(int)floatValue;
  13399. }
  13400. pNode->public_trace=intValue;
  13401. return TCL_OK;
  13402. }
  13403. case CSTRUCT_ENTITY_REPAINT: {
  13404. int intValue;
  13405. double floatValue;
  13406. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13407. Tcl_ResetResult(interp);
  13408. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13409. intValue=(int)floatValue;
  13410. }
  13411. pNode->public_repaint=intValue;
  13412. return TCL_OK;
  13413. }
  13414. case CSTRUCT_ENTITY_VISIBLE: {
  13415. int intValue;
  13416. double floatValue;
  13417. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13418. Tcl_ResetResult(interp);
  13419. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13420. intValue=(int)floatValue;
  13421. }
  13422. pNode->public_visible=intValue;
  13423. return TCL_OK;
  13424. }
  13425. case CSTRUCT_ENTITY_MOVED: {
  13426. int intValue;
  13427. double floatValue;
  13428. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13429. Tcl_ResetResult(interp);
  13430. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13431. intValue=(int)floatValue;
  13432. }
  13433. pNode->public_moved=intValue;
  13434. return TCL_OK;
  13435. }
  13436. case CSTRUCT_ENTITY_CHANGED: {
  13437. int intValue;
  13438. double floatValue;
  13439. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13440. Tcl_ResetResult(interp);
  13441. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13442. intValue=(int)floatValue;
  13443. }
  13444. pNode->public_changed=intValue;
  13445. return TCL_OK;
  13446. }
  13447. case CSTRUCT_ENTITY_OPEN: {
  13448. int intValue;
  13449. double floatValue;
  13450. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13451. Tcl_ResetResult(interp);
  13452. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13453. intValue=(int)floatValue;
  13454. }
  13455. pNode->public_open=intValue;
  13456. return TCL_OK;
  13457. }
  13458. case CSTRUCT_ENTITY_CLASS: {
  13459. char *str;
  13460. str=Tcl_GetString(value);
  13461. if(str) {
  13462. pNode->public_class=str[0];
  13463. }
  13464. return TCL_OK;
  13465. }
  13466. case CSTRUCT_ENTITY_PARENT: {
  13467. Roid roidValue;
  13468. if(Irm_GetRoidFromObj(interp,value,&roidValue)) return TCL_ERROR;
  13469. pNode->public_parent=(Roid)roidValue;
  13470. return TCL_OK;
  13471. }
  13472. case CSTRUCT_ENTITY_SYNTHETIC: {
  13473. int intValue;
  13474. double floatValue;
  13475. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13476. Tcl_ResetResult(interp);
  13477. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13478. intValue=(int)floatValue;
  13479. }
  13480. pNode->public_synthetic=intValue;
  13481. return TCL_OK;
  13482. }
  13483. case CSTRUCT_ENTITY_HIGHLIGHT: {
  13484. int intValue;
  13485. double floatValue;
  13486. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13487. Tcl_ResetResult(interp);
  13488. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13489. intValue=(int)floatValue;
  13490. }
  13491. pNode->public_highlight=intValue;
  13492. return TCL_OK;
  13493. }
  13494. case CSTRUCT_ENTITY_DRAWN: {
  13495. int intValue;
  13496. double floatValue;
  13497. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13498. Tcl_ResetResult(interp);
  13499. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13500. intValue=(int)floatValue;
  13501. }
  13502. pNode->public_drawn=intValue;
  13503. return TCL_OK;
  13504. }
  13505. case CSTRUCT_ENTITY_NCHILD: {
  13506. int intValue;
  13507. double floatValue;
  13508. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13509. Tcl_ResetResult(interp);
  13510. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13511. intValue=(int)floatValue;
  13512. }
  13513. pNode->public_nchild=intValue;
  13514. return TCL_OK;
  13515. }
  13516. case CSTRUCT_ENTITY_ONCOUNT: {
  13517. int intValue;
  13518. double floatValue;
  13519. if(Tcl_GetIntFromObj(interp,value,&intValue)) {
  13520. Tcl_ResetResult(interp);
  13521. if(Tcl_GetDoubleFromObj(interp,value,&floatValue)) return TCL_ERROR;
  13522. intValue=(int)floatValue;
  13523. }
  13524. pNode->public_oncount=intValue;
  13525. return TCL_OK;
  13526. }
  13527. }
  13528. return TCL_OK;
  13529. }
  13530. /* Entity_StructSetGroup */
  13531. void Entity_StructSetGroup(Entity *p,Roid groupid){
  13532. p->public_groupid=groupid;
  13533. }
  13534. /* Entity_StructSetType */
  13535. void Entity_StructSetType(Entity *p,Entity *pType){
  13536. p->pType=pType;
  13537. if(pType) {
  13538. if(pType->public_class=='g') {
  13539. p->gType=pType;
  13540. }
  13541. }
  13542. }
  13543. /* Entity_StructSizeZ */
  13544. int Entity_StructSizeZ(Entity *pNode){
  13545. int zheight=TypeSpec_GetInt(pNode,"size.z");
  13546. return zheight;
  13547. }
  13548. /* Entity_StructValueOffset */
  13549. int Entity_StructValueOffset(Tcl_Interp *interp,Tcl_Obj *pObj,int *pIndex,int *pType){
  13550. /*
  13551. ** Given the name of one of the arState[] values in the Entity structure,
  13552. ** return the index of the particular arState[]. Return TCL_OK.
  13553. **
  13554. ** Leave an error message in interp and return TCL_ERROR if
  13555. ** anything goes wrong.
  13556. */
  13557.  
  13558. int lo, hi, mid, c, max, i;
  13559. int nName;
  13560. const char *zName;
  13561. const struct OdieParamNameMap *aParam = Entity_canonicalNameMap;
  13562.  
  13563. lo = 0;
  13564. hi = max = CSTRUCT_ENTITY_AliasCount - 1;
  13565. zName = Tcl_GetStringFromObj(pObj, &nName);
  13566. mid = (lo+hi)/2;
  13567. if(nName>32) {
  13568. nName=32;
  13569. }
  13570. while( lo<=hi ){
  13571. mid = (lo+hi)/2;
  13572. c = strncmp(zName, aParam[mid].zName, nName);
  13573. if( c<0 ){
  13574. hi = mid-1;
  13575. }else if( c>0 ){
  13576. lo = mid+1;
  13577. }else if(
  13578. (mid>0 && strncmp(zName, aParam[mid-1].zName, nName)==0) ||
  13579. (mid<max && strncmp(zName, aParam[mid+1].zName, nName)==0)
  13580. ){
  13581. i = mid;
  13582. while( i>0 && strncmp(zName, aParam[i-1].zName, nName)==0 ){
  13583. i--;
  13584. }
  13585. if( strlen(aParam[i].zName)==nName ){
  13586. *pIndex = aParam[i].iCode;
  13587. *pType = aParam[i].pType;
  13588. return TCL_OK;
  13589. }
  13590. if(interp) {
  13591. Tcl_AppendResult(interp, "ambiguous parameter:", 0);
  13592. do{
  13593. Tcl_AppendResult(interp, " ", aParam[i++].zName, 0);
  13594. }while( i<=max && strncmp(zName, aParam[i].zName, nName)==0 );
  13595. }
  13596. return TCL_ERROR;
  13597. }else{
  13598. *pIndex = aParam[mid].iCode;
  13599. *pType = aParam[mid].pType;
  13600. return TCL_OK;
  13601. }
  13602. }
  13603. if(interp) {
  13604. Tcl_AppendResult(interp, "unknown parameter \"", zName,
  13605. "\" - nearby choices:", 0);
  13606. for(i=mid-3; i<mid+3; i++){
  13607. if( i<0 || i>max ) continue;
  13608. Tcl_AppendResult(interp, " ", aParam[i].zName, 0);
  13609. }
  13610. }
  13611. return TCL_ERROR;
  13612. }
  13613. /* Entity_StructWith */
  13614. void Entity_StructWith(Tcl_Interp *interp,Entity *p,int virtual,Tcl_Obj **objvPtr){
  13615. int i;
  13616. if (virtual) {
  13617. Entity_With(interp,p->pType,NULL);
  13618. }
  13619. /* Finaly, Add the Tcl Data */
  13620. for(i=0;i<CSTRUCT_ENTITY_Count;i++) {
  13621. Tcl_Obj *newElement=Entity_StructGet(p,i);
  13622. Tcl_Obj *fieldName=Odie_LiteralStringObj(Entity_paramNameMap[i].zName);
  13623. if(objvPtr) {
  13624. objvPtr[i*2]=fieldName;
  13625. objvPtr[i*2+1]=newElement;
  13626. }
  13627. Tcl_ObjSetVar2(interp,fieldName,NULL,newElement,0);
  13628. }
  13629. if(virtual) {
  13630. Entity_StructWithLocation(interp,p);
  13631. }
  13632. }
  13633. /* Entity_StructWithLocation */
  13634. void Entity_StructWithLocation(Tcl_Interp *interp,Entity *pNode){}
  13635. /* Entity_Unlink */
  13636. void Entity_Unlink(Entity *objPtr){
  13637. Tcl_HashEntry *pEntry;
  13638.  
  13639. if (!objPtr) return;
  13640. if(CurrentSim->GlobalSim) {
  13641. pEntry=Tcl_FindHashEntry(&CurrentSim->GlobalSim->EntityIdSet,(const char *)objPtr->name);
  13642. } else {
  13643. pEntry=Tcl_FindHashEntry(&CurrentSim->EntityIdSet,(const char *)objPtr->name);
  13644. }
  13645. if(pEntry) {
  13646. Tcl_DeleteHashEntry(pEntry);
  13647. }
  13648. #ifdef build_IRM
  13649. if(objPtr->public_class=='v') {
  13650. Crew *pNode=Crew_ById(objPtr->id,0);
  13651. if(pNode) {
  13652. Crew_Unlink(pNode);
  13653. Crew_Delete(pNode);
  13654. }
  13655. }
  13656. if(objPtr->public_class=='p') {
  13657. Portal *pNode=Portal_ById(objPtr->id,0);
  13658. if(pNode) {
  13659. Portal_Unlink(pNode);
  13660. Portal_Delete(pNode);
  13661. }
  13662. }
  13663. if(objPtr->public_class=='k') {
  13664. SimLink *pNode=SimLink_ById(objPtr->id,0);
  13665. if(pNode) {
  13666. SimLink_Unlink(pNode);
  13667. SimLink_Delete(pNode);
  13668. }
  13669. }
  13670. if(objPtr->public_class=='e') {
  13671. SimNode *pNode=SimNode_ById(objPtr->id,0);
  13672. if(pNode) {
  13673. if(pNode->aLink->pCommon->public_rupture_node == pNode->id) {
  13674. /*
  13675. ** Run link repair for rupture nodes instead of delete simnode
  13676. */
  13677. SimLink_Repair(NULL,pNode->aLink->pCommon);
  13678. } else {
  13679. SimNode_Unlink(pNode);
  13680. SimNode_Delete(pNode);
  13681. }
  13682. }
  13683. }
  13684. #endif
  13685. }
  13686. /* Entity_With */
  13687. void Entity_With(Tcl_Interp *interp,Entity *e,Tcl_HashTable *local){
  13688. Tcl_HashTable *localDict=NULL;
  13689. Entity *p=NULL;
  13690. Entity *pStack[10];
  13691. int i,count=-1;
  13692.  
  13693. p=e;
  13694. while(p && count<10) {
  13695. count++;
  13696. pStack[count]=p;
  13697. p=p->pType;
  13698. }
  13699. /*
  13700. ** Add the minimum specs for the class
  13701. */
  13702. for(i=count;i>=0;i--) {
  13703. p=pStack[i];
  13704. localDict=p->infoDict;
  13705. if(localDict) {
  13706. Tcl_HashSearch searchPtr;
  13707. Tcl_HashEntry *i;
  13708. for(i=Tcl_FirstHashEntry(localDict,&searchPtr); i ; i = Tcl_NextHashEntry(&searchPtr)) {
  13709. Tcl_Obj *pKey,*pValue;
  13710. pKey=Odie_LiteralStringObj(Tcl_GetHashKey(localDict,i));
  13711. pValue=(Tcl_Obj *)Tcl_GetHashValue(i);
  13712. Tcl_ObjSetVar2(interp,pKey,NULL,pValue,0);
  13713. }
  13714. }
  13715. }
  13716. localDict=local;
  13717. if(localDict) {
  13718. Tcl_HashSearch searchPtr;
  13719. Tcl_HashEntry *i;
  13720. for(i=Tcl_FirstHashEntry(localDict,&searchPtr); i ; i = Tcl_NextHashEntry(&searchPtr)) {
  13721. Tcl_Obj *pKey,*pValue;
  13722. pKey=Odie_LiteralStringObj(Tcl_GetHashKey(localDict,i));
  13723. pValue=(Tcl_Obj *)Tcl_GetHashValue(i);
  13724. Tcl_ObjSetVar2(interp,pKey,NULL,pValue,0);
  13725. }
  13726. }
  13727. }
  13728. #define ENTITY_SEARCH_NCOUNT 15
  13729. /* *SimType_ById */
  13730. Entity *SimType_ById(Roid id, int createFlag){
  13731. /*
  13732. ** Return a pointer to a SimType with the given ID. Return NULL
  13733. ** if there is no such type. Create a new one if the createFlag
  13734. ** is true and the type does not previously exist.
  13735. */
  13736. Tcl_HashEntry *pEntry;
  13737. if(CurrentSim->GlobalSim) {
  13738. pEntry=Tcl_FindHashEntry(&CurrentSim->GlobalSim->SimTypeIdSet,(char *)id);
  13739. } else {
  13740. pEntry=Tcl_FindHashEntry(&CurrentSim->SimTypeIdSet,(char *)id);
  13741. }
  13742. if(pEntry) {
  13743. return (Entity*)Tcl_GetHashValue(pEntry);
  13744. }
  13745. if(createFlag) {
  13746. int isNew;
  13747. Entity *p;
  13748. if(CurrentSim->GlobalSim) {
  13749. pEntry = Tcl_CreateHashEntry(&CurrentSim->GlobalSim->SimTypeIdSet,(char *)id, &isNew);
  13750. } else {
  13751. pEntry = Tcl_CreateHashEntry(&CurrentSim->SimTypeIdSet,(char *)id, &isNew);
  13752. }
  13753. p = (Entity *)Odie_Alloc( sizeof(*p) );
  13754. p->id = id;
  13755. p->pType=NULL;
  13756. Entity_StructAlloc(p);
  13757. p->public_is_type=1;
  13758. Tcl_SetHashValue(pEntry,(ClientData)p);
  13759.  
  13760. return p;
  13761. }
  13762. return NULL;
  13763. }
  13764. /* *SimType_ByName */
  13765. Entity *SimType_ByName(char *idstring, int createFlag){
  13766. Roid i=-1;
  13767. i=Odie_RoidFromString(idstring,'y');
  13768.  
  13769. if(i<0) {
  13770. return NULL;
  13771. }
  13772. return SimType_ById(i,createFlag);
  13773. }
  13774. /* *SimType_First */
  13775. Tcl_HashEntry *SimType_First(Simulator *sim,Tcl_HashSearch *search){
  13776. /*
  13777. ** Return the first entity in a list of them all
  13778. */
  13779. if(sim->GlobalSim) {
  13780. return Tcl_FirstHashEntry(&sim->GlobalSim->SimTypeIdSet,search);
  13781. } else {
  13782. return Tcl_FirstHashEntry(&sim->SimTypeIdSet,search);
  13783. }
  13784. }
  13785. /* *SimType_GroupToTclObj */
  13786. Tcl_Obj *SimType_GroupToTclObj(Entity *pNode){
  13787. Roid groupid;
  13788. if(!pNode) {
  13789. return Tcl_NewBooleanObj(0);
  13790. }
  13791. groupid=SimType_StructGetGroup(pNode);
  13792. if(!groupid) {
  13793. return Tcl_NewBooleanObj(0);
  13794. }
  13795. return Irm_NewRoidObj(groupid);
  13796. }
  13797. /* *SimType_Identify */
  13798. Tcl_Obj *SimType_Identify(Entity *pNode){
  13799. if(!pNode) {
  13800. return Irm_NewRoidObj(0);
  13801. }
  13802. return Irm_NewRoidObj(pNode->id);
  13803. }
  13804. /* *SimType_PublicId */
  13805. Tcl_Obj *SimType_PublicId(Entity *pNode){
  13806. char idstring[64];
  13807. if(!pNode) {
  13808. return Irm_NewRoidObj(0);
  13809. }
  13810. if(pNode->pType) {
  13811. if(pNode->pType->name!=NULL) {
  13812. return Odie_LiteralStringObj(pNode->pType->name);
  13813. }
  13814. }
  13815. sprintf(idstring,"y%d",pNode->id);
  13816. return Odie_LiteralStringObj(idstring);
  13817. }
  13818. /* *SimType_StructGetType */
  13819. Entity *SimType_StructGetType(Entity *p){
  13820. if(p->pType) {
  13821. return Entity_StructGetType(p->pType);
  13822. }
  13823. return NULL;
  13824. }
  13825. /* *SimType_StructToDict */
  13826. Tcl_Obj *SimType_StructToDict(Tcl_Interp *interp,Entity *p,int virtual){
  13827. Tcl_Obj *pResult=NULL;
  13828. if (virtual) {
  13829. pResult=Entity_GetDict(p->pType,NULL);
  13830. }
  13831. return pResult;
  13832. }
  13833. /* *SimType_TypeToTclObj */
  13834. Tcl_Obj *SimType_TypeToTclObj(Entity *pNode){
  13835. Entity *pType;
  13836. if(!pNode) {
  13837. return Tcl_NewBooleanObj(0);
  13838. }
  13839. pType=SimType_StructGetType(pNode);
  13840. if(!pType) {
  13841. return Tcl_NewBooleanObj(0);
  13842. }
  13843. return Irm_NewRoidObj(pType->id);
  13844. }
  13845. /* SimType_ApplySettings */
  13846. inline extern void SimType_ApplySettings(Entity *p){
  13847. /* Default implementation does nothing */
  13848. }
  13849. /* SimType_FromTclObj */
  13850. int SimType_FromTclObj(Tcl_Interp *interp, Tcl_Obj *pObj, Entity **ppEntity){
  13851. /*
  13852. ** Find a SimType given a Tcl_Obj that contains the SimType ID.
  13853. ** Leave an error message in interp and return TCL_ERROR if anything
  13854. ** goes wrong.
  13855. */
  13856. Roid i=-1;
  13857. i=Odie_RoidFromString(Tcl_GetString(pObj),'y');
  13858.  
  13859. if(i<0) {
  13860. if(interp) {
  13861. Tcl_AppendResult(interp, "no such SimType: ",
  13862. Tcl_GetStringFromObj(pObj, 0), 0);
  13863. }
  13864. }
  13865. *ppEntity = SimType_ById(i, 0);
  13866. if( *ppEntity==0 ){
  13867. if(interp) {
  13868. Tcl_AppendResult(interp, "no such SimType: ",
  13869. Tcl_GetStringFromObj(pObj, 0), 0);
  13870. }
  13871. return TCL_ERROR;
  13872. }
  13873. return TCL_OK;
  13874. }
  13875. /* SimType_Module_Advance */
  13876. void SimType_Module_Advance(Simulator *ActiveSim,int clocktime){}
  13877. /* SimType_nodeeval */
  13878. int SimType_nodeeval(Tcl_Interp *interp,Entity *p,Tcl_Obj *body,int writeback){
  13879. Tcl_Obj *id;
  13880. int i,len;
  13881. Tcl_Obj *varv[CSTRUCT_ENTITY_Count*2];
  13882. int result;
  13883.  
  13884. Entity_StructWith(interp,p,1,varv);
  13885. id=SimType_Identify(p);
  13886. Tcl_ObjSetVar2(interp,Odie_LiteralStringObj("id"),NULL,id,0);
  13887. Tcl_ObjSetVar2(interp,Odie_LiteralStringObj("typeid"),NULL,SimType_TypeToTclObj(p),0);
  13888. Tcl_ObjSetVar2(interp,Odie_LiteralStringObj("groupid"),NULL,SimType_GroupToTclObj(p),0);
  13889. /*
  13890. for(i=0;i<CSTRUCT_ENTITY_Count*2;i++) {
  13891. Tcl_IncrRefCount(varv[i]);
  13892. }
  13893. */
  13894. result=Tcl_EvalObjEx(interp, body, 0);
  13895.  
  13896. if(result!=TCL_OK) {
  13897. return result;
  13898. }
  13899. if(writeback){
  13900. /*
  13901. ** Read values back into the dict
  13902. ** For now, we limit writeback to state variables
  13903. ** And we don't care about garbage values
  13904. */
  13905. int changed=0;
  13906. for(i=0;i<CSTRUCT_ENTITY_Count*2;i+=2) {
  13907. Tcl_Obj *newValue;
  13908. int offset;
  13909. int type;
  13910. newValue=Tcl_ObjGetVar2(interp,varv[i],(Tcl_Obj*)NULL,0);
  13911. if(newValue==varv[i+1]) {
  13912. /* Undocumented, unsanctioned, but it works in practice
  13913. ** If the pointer hasn't changed, neither has the value
  13914. */
  13915. continue;
  13916. }
  13917. if(!newValue) {
  13918. /* Variable must have been unset... move along */
  13919. continue;
  13920. }
  13921. if( Entity_StructValueOffset(0, varv[i], &offset, &type) == TCL_OK ) {
  13922. Entity_StructSet(interp,p,offset,newValue);
  13923. changed++;
  13924. }
  13925. }
  13926. if(changed) {
  13927. Entity_ApplySettings(p);
  13928. }
  13929. }
  13930. /*
  13931. for(i=0;i<CSTRUCT_ENTITY_Count*2;i++) {
  13932. Tcl_DecrRefCount(varv[i]);
  13933. }
  13934. */
  13935. return TCL_OK;
  13936. }
  13937. /* SimType_Rewind */
  13938. void SimType_Rewind(Entity *p, int revert){}
  13939. /* SimType_StructGetGroup */
  13940. Roid SimType_StructGetGroup(Entity *p){
  13941. if(!p) {
  13942. return 0;
  13943. }
  13944. if (p->public_class=='g') {
  13945. return p->id;
  13946. }
  13947. if(p->public_groupid) {
  13948. return p->public_groupid;
  13949. }
  13950. if(p->public_parent) {
  13951. Entity *pType=SimType_ById(p->public_parent,0);
  13952. if(pType) {
  13953. if (pType->public_class=='g') {
  13954. return pType->id;
  13955. }
  13956. /* Otherwise, keep looking for parents */
  13957. return SimType_StructGetGroup(pType);
  13958. }
  13959. }
  13960. return 0;
  13961. }
  13962. /* SimType_StructSetGroup */
  13963. void SimType_StructSetGroup(Entity *p,Roid groupid){
  13964. p->public_groupid=groupid;
  13965. }
  13966. /* SimType_StructSetType */
  13967. void SimType_StructSetType(Entity *p,Entity *pType){
  13968. if(!p->pType) {
  13969. return;
  13970. }
  13971. Entity_StructSetType(p->pType,pType);
  13972. }
  13973. /* SimType_StructWith */
  13974. void SimType_StructWith(Tcl_Interp *interp,Entity *p,int virtual){
  13975. if (virtual) {
  13976. Entity_With(interp,p->pType,p->infoDict);
  13977. }
  13978. }
  13979. /* SimType_Unlink */
  13980. void SimType_Unlink(Entity *objPtr){
  13981. Tcl_HashEntry *pEntry;
  13982. if(CurrentSim->GlobalSim) {
  13983. pEntry=Tcl_FindHashEntry(&CurrentSim->GlobalSim->SimTypeIdSet,(char *)objPtr->id);
  13984. } else {
  13985. pEntry=Tcl_FindHashEntry(&CurrentSim->SimTypeIdSet,(char *)objPtr->id);
  13986. }
  13987. if(pEntry) {
  13988. Tcl_DeleteHashEntry(pEntry);
  13989. }
  13990. }
  13991. /* TypeSpec_SetInt */
  13992. void TypeSpec_SetInt(Entity *pType,char *field, int value){
  13993. Tcl_Obj *newValue;
  13994. if(!pType) return;
  13995. newValue=Tcl_NewIntObj(value);
  13996. Odie_HashPut(&pType->infoDict,field,newValue);
  13997. //Tcl_DecrRefCount(newValue);
  13998. }
  13999. /* TypeSpec_SetReal */
  14000. void TypeSpec_SetReal(Entity *pType,char *field, IrmReal value){
  14001. Tcl_Obj *newValue;
  14002. if(!pType) return;
  14003. double fabsvalue=fabs(value);
  14004. if(fabsvalue == value && fabsvalue < 10 ) {
  14005. TypeSpec_SetInt(pType,field,(int)value);
  14006. return;
  14007. }
  14008. newValue=Tcl_NewDoubleObj((double)value);
  14009. Odie_HashPut(&pType->infoDict,field,newValue);
  14010. //Tcl_DecrRefCount(newValue);
  14011. }
  14012. /* TypeSpec_SetWideInt */
  14013. void TypeSpec_SetWideInt(Entity *pType, char *field, Tcl_WideInt value){
  14014. Tcl_Obj *newValue;
  14015. if(!pType) return;
  14016. if(value > -10 && value < 10) {
  14017. TypeSpec_SetInt(pType,field,(int)value);
  14018. return;
  14019. }
  14020. newValue=Tcl_NewWideIntObj(value);
  14021. Odie_HashPut(&pType->infoDict,field,newValue);
  14022. //Tcl_DecrRefCount(newValue);
  14023. }
  14024. /* TypeSpec_Exists */
  14025. IrmReal TypeSpec_Exists(Entity *pType, char *field){
  14026. Tcl_Obj *result=NULL;
  14027. if(field && pType) {
  14028. result=Entity_GetField(pType->pType,pType->infoDict,field);
  14029. }
  14030. if(result) {
  14031. return 1;
  14032. }
  14033. return 0;
  14034. }
  14035. /* TypeSpec_GetReal */
  14036. IrmReal TypeSpec_GetReal(Entity *pType, char *field){
  14037. Tcl_Obj *result=NULL;
  14038. if(field && pType) {
  14039. result=Entity_GetField(pType->pType,pType->infoDict,field);
  14040. }
  14041. if(result) {
  14042. double s;
  14043. if (Tcl_GetDoubleFromObj(NULL,result,&s)==TCL_OK) {
  14044. return s;
  14045. }
  14046. }
  14047. return 0.0;
  14048. }
  14049. /* TypeSpec_GetReal_Or_Default */
  14050. IrmReal TypeSpec_GetReal_Or_Default(Entity *pType, char *field,IrmReal defaultValue){
  14051. Tcl_Obj *result=NULL;
  14052. if(field && pType) {
  14053. result=Entity_GetField(pType->pType,pType->infoDict,field);
  14054. }
  14055. if(result) {
  14056. double s;
  14057. if (Tcl_GetDoubleFromObj(NULL,result,&s)==TCL_OK) {
  14058. return s;
  14059. }
  14060. }
  14061. return defaultValue;
  14062. }
  14063. /* TypeSpec_GetInt */
  14064. int TypeSpec_GetInt(Entity *pType, char *field){
  14065. Tcl_Obj *result=NULL;
  14066. if(field && pType) {
  14067. result=Entity_GetField(pType->pType,pType->infoDict,field);
  14068. }
  14069. if(result) {
  14070. int sint;
  14071. double s;
  14072. if (Tcl_GetIntFromObj(NULL,result,&sint)==TCL_OK) {
  14073. return sint;
  14074. }
  14075. if (Tcl_GetDoubleFromObj(NULL,result,&s)==TCL_OK) {
  14076. return (int)round(s);
  14077. }
  14078. }
  14079. return 0;
  14080. }
  14081. /* TypeSpec_GetInt_or_Default */
  14082. int TypeSpec_GetInt_or_Default(Entity *pType, char *field,int dValue){
  14083. Tcl_Obj *result=NULL;
  14084. if(field && pType) {
  14085. result=Entity_GetField(pType->pType,pType->infoDict,field);
  14086. }
  14087. if(result) {
  14088. int sint;
  14089. double s;
  14090. if (Tcl_GetIntFromObj(NULL,result,&sint)==TCL_OK) {
  14091. return sint;
  14092. }
  14093. if (Tcl_GetDoubleFromObj(NULL,result,&s)==TCL_OK) {
  14094. return (int)round(s);
  14095. }
  14096. }
  14097. return dValue;
  14098. }
  14099. /* TypeSpec_WideInt */
  14100. Tcl_WideInt TypeSpec_WideInt(Entity *pType, char *field){
  14101. Tcl_Obj *result=NULL;
  14102. if(field && pType) {
  14103. result=Entity_GetField(pType->pType,pType->infoDict,field);
  14104. }
  14105. if(result) {
  14106. Tcl_WideInt c;
  14107. if(Tcl_GetWideIntFromObj(NULL,result,&c)==TCL_OK) {
  14108. return c;
  14109. }
  14110. }
  14111. return 0;
  14112. }
  14113. /* *TypeSpec_GetTclObj */
  14114. Tcl_Obj *TypeSpec_GetTclObj(Entity *pType, char *field){
  14115. Tcl_Obj *result=NULL;
  14116.  
  14117. if(field && pType) {
  14118. result=Entity_GetField(pType->pType,pType->infoDict,field);
  14119. }
  14120. if(result) {
  14121. return result;
  14122. }
  14123. return Tcl_NewObj();
  14124. }
  14125. /* *TypeSpec_GetTclObj_OR_NULL */
  14126. Tcl_Obj *TypeSpec_GetTclObj_OR_NULL(Entity *pType, char *field){
  14127. Tcl_Obj *result=NULL;
  14128.  
  14129. if(field && pType) {
  14130. result=Entity_GetField(pType->pType,pType->infoDict,field);
  14131. }
  14132. return result;
  14133. }
  14134. /* *TypeSpec_GetLogicSet */
  14135. Tcl_Obj *TypeSpec_GetLogicSet(Entity *pType, char *field){
  14136. if(field && pType) {
  14137. return Entity_GetField(pType->pType,pType->infoDict,field);
  14138. }
  14139. return NULL;
  14140. }
  14141. /* END generate-cfile-functions */
  14142. /* BEGIN generate-cfile-tclapi */
  14143. /* Tcl Proc ::odiemath::distance */
  14144. static int TclCmd_odiemath_distance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14145. int i;
  14146. double result;
  14147. if( objc<1 ){
  14148. Tcl_WrongNumArgs(interp, 1, objv, "i1 i2 ?j1 j2? ?k1 k2?");
  14149. return TCL_ERROR;
  14150. }
  14151. result=0.0;
  14152. for(i=1;i<objc;i+=2) {
  14153. double a,b,dx;
  14154. if(Tcl_GetDoubleFromObj(interp,objv[i],&a)) return TCL_ERROR;
  14155. if(i+1>=objc) {
  14156. Tcl_AppendResult(interp, "Odd number of arguments",(char*)0);
  14157. return TCL_ERROR;
  14158. }
  14159. if(Tcl_GetDoubleFromObj(interp,objv[i+1],&b)) return TCL_ERROR;
  14160. dx=b-a;
  14161. result=result+dx*dx;
  14162. }
  14163. result=sqrt(result);
  14164. Tcl_SetObjResult(interp,Tcl_NewDoubleObj(result));
  14165. return TCL_OK;
  14166. }
  14167. /* Tcl Proc ::odiemath::dist3d */
  14168. static int TclCmd_odiemath_dist3d(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14169. double result,ax,ay,az,bx,by,bz,dx,dy,dz;
  14170. if( objc!=7 ){
  14171. Tcl_WrongNumArgs(interp, 1, objv, "x0 y0 z0 x1 y1 z1");
  14172. return TCL_ERROR;
  14173. }
  14174. result=0.0;
  14175. if(Tcl_GetDoubleFromObj(interp,objv[1],&ax)) return TCL_ERROR;
  14176. if(Tcl_GetDoubleFromObj(interp,objv[2],&ay)) return TCL_ERROR;
  14177. if(Tcl_GetDoubleFromObj(interp,objv[3],&az)) return TCL_ERROR;
  14178. if(Tcl_GetDoubleFromObj(interp,objv[4],&bx)) return TCL_ERROR;
  14179. if(Tcl_GetDoubleFromObj(interp,objv[5],&by)) return TCL_ERROR;
  14180. if(Tcl_GetDoubleFromObj(interp,objv[6],&bz)) return TCL_ERROR;
  14181. dx=bx-ax;
  14182. dy=by-ay;
  14183. dz=bz-az;
  14184.  
  14185. result=sqrt(dx*dx + dy*dy + dz*dz);
  14186. Tcl_SetObjResult(interp,Tcl_NewDoubleObj(result));
  14187. return TCL_OK;
  14188. }
  14189. /* Tcl Proc ::odiemath::grid_hex */
  14190. static int TclCmd_odiemath_grid_hex(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14191. double grid, x, y;
  14192. int gx,gy;
  14193. Tcl_Obj *pResult;
  14194.  
  14195. if( objc != 4 ){
  14196. Tcl_WrongNumArgs(interp, 1, objv, "gridsize x y");
  14197. return TCL_ERROR;
  14198. }
  14199. if(Tcl_GetDoubleFromObj(interp,objv[1],&grid)) return TCL_ERROR;
  14200. if(Tcl_GetDoubleFromObj(interp,objv[2],&x)) return TCL_ERROR;
  14201. if(Tcl_GetDoubleFromObj(interp,objv[3],&y)) return TCL_ERROR;
  14202. pResult=Tcl_NewObj();
  14203. gy=(int)round(y/grid);
  14204. if(gy%2==1){
  14205. gx=(int)round((x-grid/2)/grid);
  14206. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(grid*gx+grid/2));
  14207. } else {
  14208. gx=(int)round(x/grid);
  14209. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(grid*gx));
  14210. }
  14211. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(grid*gy));
  14212. Tcl_SetObjResult(interp, pResult);
  14213. return TCL_OK;
  14214. }
  14215. /* Tcl Proc ::odiemath::grid_round */
  14216. static int TclCmd_odiemath_grid_round(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14217. double x,q;
  14218. int i;
  14219. Tcl_Obj *pResult;
  14220. pResult=Tcl_NewObj();
  14221. for(i=1;i<objc;i++) {
  14222. if(Tcl_GetDoubleFromObj(interp,objv[i],&x)) {
  14223. Tcl_DecrRefCount(pResult);
  14224. return TCL_ERROR;
  14225. }
  14226. q=OdieGrain*round(x/OdieGrain);
  14227. if(x-q>(OdieGrain*0.5)) {
  14228. q+=OdieGrain;
  14229. }
  14230. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(q));
  14231. }
  14232. Tcl_SetObjResult(interp, pResult);
  14233. return TCL_OK;
  14234. }
  14235. /* Tcl Proc ::odiemath::grid_square */
  14236. static int TclCmd_odiemath_grid_square(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14237. double grid;
  14238. double x;
  14239. double y;
  14240. Tcl_Obj *pResult;
  14241. if( objc < 3 ){
  14242. Tcl_WrongNumArgs(interp, 1, objv, "gridsize x y...");
  14243. return TCL_ERROR;
  14244. }
  14245. if(Tcl_GetDoubleFromObj(interp,objv[1],&grid)) return TCL_ERROR;
  14246. if(Tcl_GetDoubleFromObj(interp,objv[2],&x)) return TCL_ERROR;
  14247. if(Tcl_GetDoubleFromObj(interp,objv[3],&y)) return TCL_ERROR;
  14248. pResult=Tcl_NewObj();
  14249. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(grid*round(x/grid)));
  14250. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(grid*round(y/grid)));
  14251. Tcl_SetObjResult(interp, pResult);
  14252. return TCL_OK;
  14253. }
  14254. /* Tcl Proc ::odiemath::list_round */
  14255. static int TclCmd_odiemath_list_round(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14256. int i, n;
  14257. double factor;
  14258. Tcl_Obj *pResult;
  14259. if( objc < 3 ){
  14260. Tcl_WrongNumArgs(interp, 1, objv, "gridsize list\ngridsize element ?element?...");
  14261. return TCL_ERROR;
  14262. }
  14263. if(Tcl_GetDoubleFromObj(interp,objv[1],&factor)) return TCL_ERROR;
  14264. if(objc==3) {
  14265. if( Tcl_ListObjLength(interp, objv[2], &n) ) return TCL_ERROR;
  14266. pResult=Tcl_NewObj();
  14267. for(i=0;i<n;i++) {
  14268. double thisval,remainder;
  14269. Tcl_Obj *pObj;
  14270. Tcl_ListObjIndex(0, objv[2], i, &pObj);
  14271. if(Tcl_GetDoubleFromObj(interp,pObj,&thisval)) {
  14272. Tcl_DecrRefCount(pResult);
  14273. return TCL_ERROR;
  14274. }
  14275. remainder=fmod(thisval,factor);
  14276. Tcl_ListObjAppendElement(interp, pResult, ODIE_NewFuzzyObj(thisval-remainder));
  14277. }
  14278. } else {
  14279. pResult=Tcl_NewObj();
  14280. for(i=2;i<objc;i++) {
  14281. double thisval,remainder;
  14282. if(Tcl_GetDoubleFromObj(interp,objv[i],&thisval)) {
  14283. Tcl_DecrRefCount(pResult);
  14284. return TCL_ERROR;
  14285. }
  14286. remainder=fmod(thisval,factor);
  14287. Tcl_ListObjAppendElement(interp, pResult, ODIE_NewFuzzyObj(thisval-remainder));
  14288. }
  14289. }
  14290. Tcl_SetObjResult(interp,pResult);
  14291. return TCL_OK;
  14292. }
  14293. /* Tcl Proc ::odiemath::list_to_int */
  14294. static int TclCmd_odiemath_list_to_int(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14295. Tcl_Obj *pResult=Tcl_NewObj();
  14296. int i;
  14297. for(i=1;i<objc;i++) {
  14298. double thisval;
  14299. if(Tcl_GetDoubleFromObj(interp,objv[i],&thisval)) return TCL_ERROR;
  14300. Tcl_ListObjAppendElement(interp, pResult, Tcl_NewIntObj((int)thisval));
  14301. }
  14302. Tcl_SetObjResult(interp,pResult);
  14303. return TCL_OK;
  14304. }
  14305. /* Tcl Proc ::odiemath::matrix_rotate_angle */
  14306. static int TclCmd_odiemath_matrix_rotate_angle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14307. Tcl_Obj *pResult=Tcl_NewObj();
  14308. double angle;
  14309. if( (objc != 2) && (objc != 3) ){
  14310. Tcl_WrongNumArgs(interp, 1, objv, "angle ?units?");
  14311. return TCL_ERROR;
  14312. }
  14313. if(Tcl_GetDoubleFromObj(interp,objv[1],&angle)) return TCL_ERROR;
  14314. if(objc==3) {
  14315. /* Scale by the unit */
  14316. char *units;
  14317. units=Tcl_GetString(objv[2]);
  14318. if(units[0]=='d') {
  14319. angle=angle/180.0*M_PI;
  14320. } else if (units[0]=='g') {
  14321. angle=angle/200.0*M_PI;
  14322. } else if (units[0]=='r') {
  14323. } else {
  14324. Tcl_AppendResult(interp, "Unknown unit ", units, " use d[egrees], r[adians], or g[radients]. Radians are assumed",(char*)0);
  14325. return TCL_ERROR;
  14326. }
  14327. }
  14328. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(cos(angle)));
  14329. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(sin(angle)));
  14330. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(-sin(angle)));
  14331. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(cos(angle)));
  14332. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(0.0));
  14333. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(0.0));
  14334. Tcl_SetObjResult(interp, pResult);
  14335. return TCL_OK;
  14336. }
  14337. /* Tcl Proc ::odiemath::matrix_rotate_normal */
  14338. static int TclCmd_odiemath_matrix_rotate_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14339. Tcl_Obj *pResult=Tcl_NewObj();
  14340. double nx,ny,angle;
  14341.  
  14342. if( objc != 3 ){
  14343. Tcl_WrongNumArgs(interp, 1, objv, "nx ny");
  14344. return TCL_ERROR;
  14345. }
  14346. if(Tcl_GetDoubleFromObj(interp,objv[1],&nx)) return TCL_ERROR;
  14347. if(Tcl_GetDoubleFromObj(interp,objv[2],&ny)) return TCL_ERROR;
  14348. angle=atan2(ny,nx);
  14349.  
  14350. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(cos(angle)));
  14351. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(sin(angle)));
  14352. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(-sin(angle)));
  14353. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(cos(angle)));
  14354. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(0.0));
  14355. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(0.0));
  14356. Tcl_SetObjResult(interp, pResult);
  14357. return TCL_OK;
  14358. }
  14359. /* Tcl Proc ::odiemath::normal */
  14360. static int TclCmd_odiemath_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14361. double x0,y0,x1,y1;
  14362. double L,dx,dy;
  14363. Tcl_Obj *pResult;
  14364. if( objc != 5 ){
  14365. Tcl_WrongNumArgs(interp, 1, objv, "x0 y0 x1 y1");
  14366. return TCL_ERROR;
  14367. }
  14368. if(Tcl_GetDoubleFromObj(interp,objv[1],&x0)) return TCL_ERROR;
  14369. if(Tcl_GetDoubleFromObj(interp,objv[2],&y0)) return TCL_ERROR;
  14370. if(Tcl_GetDoubleFromObj(interp,objv[3],&x1)) return TCL_ERROR;
  14371. if(Tcl_GetDoubleFromObj(interp,objv[4],&y1)) return TCL_ERROR;
  14372.  
  14373. dx=x1-x0;
  14374. dy=y1-y0;
  14375. L=sqrt(dx*dx+dy*dy);
  14376. pResult=Tcl_NewObj();
  14377. if(ODIE_Real_Is_Zero(L)) {
  14378. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewIntObj(100));
  14379. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewIntObj(0));
  14380. } else {
  14381. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewIntObj((int)100*(dx/L)));
  14382. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewIntObj((int)100*(dy/L)));
  14383. }
  14384. Tcl_SetObjResult(interp, pResult);
  14385. return TCL_OK;
  14386. }
  14387. /* Tcl Proc ::odiemath::perpendicular */
  14388. static int TclCmd_odiemath_perpendicular(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14389. double x0,y0,x1,y1;
  14390. double L,dx,dy;
  14391. Tcl_Obj *pResult;
  14392. if( objc != 5 ){
  14393. Tcl_WrongNumArgs(interp, 1, objv, "x0 y0 x1 y1");
  14394. return TCL_ERROR;
  14395. }
  14396. if(Tcl_GetDoubleFromObj(interp,objv[1],&x0)) return TCL_ERROR;
  14397. if(Tcl_GetDoubleFromObj(interp,objv[2],&y0)) return TCL_ERROR;
  14398. if(Tcl_GetDoubleFromObj(interp,objv[3],&x1)) return TCL_ERROR;
  14399. if(Tcl_GetDoubleFromObj(interp,objv[4],&y1)) return TCL_ERROR;
  14400.  
  14401. dx=y1-y0;
  14402. dy=x0-x1;
  14403. L=sqrt(dx*dx+dy*dy);
  14404. pResult=Tcl_NewObj();
  14405. if(ODIE_Real_Is_Zero(L)) {
  14406. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewIntObj(100));
  14407. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewIntObj(0));
  14408. } else {
  14409. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewIntObj((int)100*(dx/L)));
  14410. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewIntObj((int)100*(dy/L)));
  14411. }
  14412. Tcl_SetObjResult(interp, pResult);
  14413. return TCL_OK;
  14414. }
  14415. /* Tcl Proc ::odiemath::normal_2d */
  14416. static int TclCmd_odiemath_normal_2d(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14417. double nx,ny,norm;
  14418. int ox,oy;
  14419. Tcl_Obj *pResult;
  14420. if( objc < 3 ){
  14421. ox=100;
  14422. oy=0;
  14423. } else {
  14424. if(Tcl_GetDoubleFromObj(interp,objv[1],&nx)) return TCL_ERROR;
  14425. if(Tcl_GetDoubleFromObj(interp,objv[2],&ny)) return TCL_ERROR;
  14426. norm=sqrt(nx*nx+ny*ny);
  14427. if(norm<=0.0) {
  14428. ox=100.0;
  14429. oy=0.0;
  14430. } else {
  14431. ox=100*nx/norm;
  14432. oy=100*ny/norm;
  14433. }
  14434. }
  14435. pResult=Tcl_NewObj();
  14436. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewIntObj(ox));
  14437. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewIntObj(oy));
  14438. Tcl_SetObjResult(interp, pResult);
  14439. return TCL_OK;
  14440. }
  14441. /* Tcl Proc ::odiemath::parallel_segment */
  14442. static int TclCmd_odiemath_parallel_segment(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14443. double x0,y0,x1,y1,offset;
  14444. double L,dx,dy;
  14445. Tcl_Obj *pResult;
  14446. if( objc != 6 ){
  14447. Tcl_WrongNumArgs(interp, 1, objv, "x0 y0 x1 y1 offset");
  14448. return TCL_ERROR;
  14449. }
  14450. if(Tcl_GetDoubleFromObj(interp,objv[1],&x0)) return TCL_ERROR;
  14451. if(Tcl_GetDoubleFromObj(interp,objv[2],&y0)) return TCL_ERROR;
  14452. if(Tcl_GetDoubleFromObj(interp,objv[3],&x1)) return TCL_ERROR;
  14453. if(Tcl_GetDoubleFromObj(interp,objv[4],&y1)) return TCL_ERROR;
  14454. if(Tcl_GetDoubleFromObj(interp,objv[5],&offset)) return TCL_ERROR;
  14455.  
  14456. dx=x0-x1;
  14457. dy=y0-y1;
  14458. L=sqrt(dx*dx+dy*dy);
  14459. if(ODIE_Real_Is_Zero(dx)) {
  14460. offset*=-1.0;
  14461. }
  14462. pResult=Tcl_NewObj();
  14463. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(x0+offset*dy/L));
  14464. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(y0+offset*dx/L));
  14465. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(x1+offset*dy/L));
  14466. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(y1+offset*dx/L));
  14467. Tcl_SetObjResult(interp, pResult);
  14468. return TCL_OK;
  14469. }
  14470. /* Tcl Proc ::odiemath::vector_length */
  14471. static int TclCmd_odiemath_vector_length(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14472. int i;
  14473. double result,sum=0.0;
  14474. if( objc<1 ){
  14475. Tcl_WrongNumArgs(interp, 1, objv, "x ?y? ?z? ?...?");
  14476. return TCL_ERROR;
  14477. }
  14478. result=0.0;
  14479. for(i=1;i<objc;i++) {
  14480. double a;
  14481. if(Tcl_GetDoubleFromObj(interp,objv[i],&a)) return TCL_ERROR;
  14482. sum+=a*a;
  14483. }
  14484. result=sqrt(sum);
  14485. Tcl_SetObjResult(interp,Tcl_NewDoubleObj(result));
  14486. return TCL_OK;
  14487. }
  14488. /* Tcl Proc ::odiemath::vector_rotate_and_size */
  14489. static int TclCmd_odiemath_vector_rotate_and_size(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14490. /*
  14491. ** Apply Matrices
  14492. */
  14493. Tcl_Obj *pResult=Tcl_NewObj();
  14494. int i;
  14495. double matA[6] = {1.0,0.0,0.0,1.0,0.0,0.0};
  14496. double nx,ny,scalex,scaley,angle;
  14497.  
  14498. if( objc < 7 ){
  14499. Tcl_WrongNumArgs(interp, 1, objv, "normalx normaly sizex sizey x1 y1 ?x2 y2?...");
  14500. return TCL_ERROR;
  14501. }
  14502.  
  14503. if(Tcl_GetDoubleFromObj(interp,objv[1],&nx)) return TCL_ERROR;
  14504. if(Tcl_GetDoubleFromObj(interp,objv[2],&ny)) return TCL_ERROR;
  14505. if(Tcl_GetDoubleFromObj(interp,objv[3],&scalex)) return TCL_ERROR;
  14506. if(Tcl_GetDoubleFromObj(interp,objv[4],&scaley)) return TCL_ERROR;
  14507.  
  14508. angle=atan2(ny,nx);
  14509. matA[0]=cos(angle);
  14510. matA[1]=sin(angle);
  14511. matA[2]=-sin(angle);
  14512. matA[3]=cos(angle);
  14513. matA[4]=0.0;
  14514. matA[5]=0.0;
  14515.  
  14516. scalex*=0.5;
  14517. scaley*=0.5;
  14518. for(i=5;i<objc;i+=2) {
  14519. double x,y,sx,sy,newx,newy;
  14520. if(Tcl_GetDoubleFromObj(interp,objv[i],&x)) return TCL_ERROR;
  14521. if(Tcl_GetDoubleFromObj(interp,objv[i+1],&y)) return TCL_ERROR;
  14522. sx=x*scalex;
  14523. sy=y*scaley;
  14524. newx=matA[0]*sx+matA[1]*sy+matA[4];
  14525. newy=matA[2]*sx+matA[3]*sy+matA[5];
  14526.  
  14527. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newx));
  14528. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newy));
  14529. }
  14530. Tcl_SetObjResult(interp, pResult);
  14531. return TCL_OK;
  14532. }
  14533. /* Tcl Proc ::odiemath::vector_scale */
  14534. static int TclCmd_odiemath_vector_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14535. Tcl_Obj *pResult=Tcl_NewObj();
  14536. int i;
  14537. double scalex,scaley;
  14538.  
  14539. if( objc < 5 ){
  14540. Tcl_WrongNumArgs(interp, 1, objv, "sizex sizey x1 y1 ?x2 y2?...");
  14541. return TCL_ERROR;
  14542. }
  14543.  
  14544. if(Tcl_GetDoubleFromObj(interp,objv[1],&scalex)) return TCL_ERROR;
  14545. if(Tcl_GetDoubleFromObj(interp,objv[2],&scaley)) return TCL_ERROR;
  14546.  
  14547. scalex*=0.5;
  14548. scaley*=0.5;
  14549. for(i=3;i<objc;i+=2) {
  14550. double x,y,sx,sy;
  14551. if(Tcl_GetDoubleFromObj(interp,objv[i],&x)) return TCL_ERROR;
  14552. if(Tcl_GetDoubleFromObj(interp,objv[i+1],&y)) return TCL_ERROR;
  14553. sx=x*scalex;
  14554. sy=y*scaley;
  14555. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(sx));
  14556. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(sy));
  14557. }
  14558. Tcl_SetObjResult(interp, pResult);
  14559. return TCL_OK;
  14560. }
  14561. /* Tcl Proc ::odiemath::vector_translate_and_zoom */
  14562. static int TclCmd_odiemath_vector_translate_and_zoom(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14563. /*
  14564. ** Apply Matrices
  14565. */
  14566.  
  14567. Tcl_Obj *pResult=Tcl_NewObj();
  14568. int i;
  14569. double zoom;
  14570. double centerx,centery;
  14571.  
  14572. if( objc < 6 ){
  14573. Tcl_WrongNumArgs(interp, 1, objv, "zoom centerx centery x1 y1 ?x2 y2?...");
  14574. return TCL_ERROR;
  14575. }
  14576. if(Tcl_GetDoubleFromObj(interp,objv[1],&zoom)) return TCL_ERROR;
  14577. if(Tcl_GetDoubleFromObj(interp,objv[2],&centerx)) return TCL_ERROR;
  14578. if(Tcl_GetDoubleFromObj(interp,objv[3],&centery)) return TCL_ERROR;
  14579. for(i=4;i<objc;i+=2) {
  14580. double x,y,newx,newy;
  14581. if(Tcl_GetDoubleFromObj(interp,objv[i],&x)) return TCL_ERROR;
  14582. if(Tcl_GetDoubleFromObj(interp,objv[i+1],&y)) return TCL_ERROR;
  14583. newx=(x/zoom)+centerx;
  14584. newy=(y/zoom)+centery;
  14585. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newx));
  14586. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newy));
  14587. }
  14588. Tcl_SetObjResult(interp, pResult);
  14589. return TCL_OK;
  14590. }
  14591. /* Tcl Proc ::odiemath::grid */
  14592. static int TclCmd_odiemath_grid(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14593. if( objc > 1 ){
  14594. if(Tcl_GetDoubleFromObj(interp,objv[1],&OdieGrain)) return TCL_ERROR;
  14595. }
  14596. Tcl_SetObjResult(interp,Tcl_NewDoubleObj(OdieGrain));
  14597. return TCL_OK;
  14598. }
  14599. /* Tcl Proc ::odiemath::tolerance */
  14600. static int TclCmd_odiemath_tolerance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14601. if( objc > 1 ){
  14602. if(Tcl_GetDoubleFromObj(interp,objv[1],&OdieTolerance)) return TCL_ERROR;
  14603. }
  14604. Tcl_SetObjResult(interp,Tcl_NewDoubleObj(OdieTolerance));
  14605. return TCL_OK;
  14606. }
  14607. /* Tcl Proc ::odie::aabb::create */
  14608. static int TclCmd_odie_aabb_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14609. MATOBJ *C;
  14610. C=Odie_MatrixObj_Create(MATFORM_aabb_xyz);
  14611. VectorXYZ_AABB_Reset(C->matrix);
  14612. if(objc==7) {
  14613. int i;
  14614. for(i=1;i<objc;i++) {
  14615. if(Tcl_GetDoubleFromObj(interp,objv[1],&C->matrix[i-1])) return TCL_ERROR;
  14616. }
  14617. } else if(objc>1) {
  14618. int i;
  14619. VectorXYZ point;
  14620. for(i=1;i<objc;i++) {
  14621. if(Odie_GetVectorXYZFromTclObj(interp,objv[i],point)) return TCL_ERROR;
  14622. VectorXYZ_AABB_Measure(point,C->matrix);
  14623. }
  14624. }
  14625. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  14626. return TCL_OK;
  14627. }
  14628. /* Tcl Proc ::odie::aabb::overlap_two_vectors */
  14629. static int TclCmd_odie_aabb_overlap_two_vectors(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14630. VectorXYZ a1,a2,b1,b2;
  14631. double c;
  14632. if( objc != 5 ){
  14633. Tcl_WrongNumArgs(interp, 1, objv, "A1 A2 B1 B2");
  14634. return TCL_ERROR;
  14635. }
  14636. if(Odie_GetVectorXYZFromTclObj(interp,objv[1],a1)) return TCL_ERROR;
  14637. if(Odie_GetVectorXYZFromTclObj(interp,objv[2],a2)) return TCL_ERROR;
  14638. if(Odie_GetVectorXYZFromTclObj(interp,objv[3],b1)) return TCL_ERROR;
  14639. if(Odie_GetVectorXYZFromTclObj(interp,objv[4],b2)) return TCL_ERROR;
  14640. c=VectorXYZ_BBOX_Overlap_TwoVectors(a1,a2,b1,b2);
  14641. Tcl_SetObjResult(interp, Tcl_NewIntObj(c));
  14642. return TCL_OK;
  14643. }
  14644. /* Tcl Proc ::odie::aabb::measure */
  14645. static int TclCmd_odie_aabb_measure(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14646. MATOBJ *C;
  14647. Tcl_Obj *varname,*pResult;
  14648. int i;
  14649. VectorXYZ point;
  14650. if( objc < 2 ){
  14651. Tcl_WrongNumArgs(interp, 1, objv, "BBOX VECTORXYZ ?VECTORXYZ..?");
  14652. return TCL_ERROR;
  14653. }
  14654. varname=Tcl_ObjGetVar2(interp,objv[1],NULL,0);
  14655. if(Odie_GetMatrixFromTclObj(interp,varname,MATFORM_aabb_xyz,&C)) return TCL_ERROR;
  14656. VectorXYZ_AABB_Normalize(C->matrix);
  14657. for(i=2;i<objc;i++) {
  14658. if(Odie_GetVectorXYZFromTclObj(interp,objv[i],point)) return TCL_ERROR;
  14659. VectorXYZ_AABB_Measure(point,C->matrix);
  14660. }
  14661. Tcl_InvalidateStringRep(varname);
  14662. return TCL_OK;
  14663. }
  14664. /* Tcl Proc ::odie::aabb::faces */
  14665. static int TclCmd_odie_aabb_faces(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14666. double VALUES[6];
  14667. double scale=1.0;
  14668. Tcl_Obj *pResult,*pRow;
  14669. if( objc != 2 && objc != 3 && objc != 7 && objc != 8){
  14670. Tcl_WrongNumArgs(interp, 1, objv, "AABB ?SCALE?\nx0 y0 z0 x1 y1 z1 ?SCALE?");
  14671. return TCL_ERROR;
  14672. }
  14673. if(objc==2 || objc==3) {
  14674. MATOBJ *A;
  14675. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_aabb_xyz,&A)) return TCL_ERROR;
  14676. if(objc==3) {
  14677. if(Tcl_GetDoubleFromObj(interp,objv[2],&scale)) {
  14678. scale=1.0;
  14679. }
  14680. }
  14681. VALUES[X_MIN_IDX]=A->matrix[X_MIN_IDX];
  14682. VALUES[Y_MIN_IDX]=A->matrix[Y_MIN_IDX];
  14683. VALUES[Z_MIN_IDX]=A->matrix[Z_MIN_IDX];
  14684. VALUES[X_MAX_IDX]=A->matrix[X_MAX_IDX];
  14685. VALUES[Y_MAX_IDX]=A->matrix[Y_MAX_IDX];
  14686. VALUES[Z_MAX_IDX]=A->matrix[Z_MAX_IDX];
  14687. } else {
  14688. if(objc==8) {
  14689. if(Tcl_GetDoubleFromObj(interp,objv[7],&scale)) {
  14690. scale=1.0;
  14691. }
  14692. }
  14693. if(Tcl_GetDoubleFromObj(interp,objv[1],&VALUES[0])!=TCL_OK) return TCL_ERROR;
  14694. if(Tcl_GetDoubleFromObj(interp,objv[2],&VALUES[1])!=TCL_OK) return TCL_ERROR;
  14695. if(Tcl_GetDoubleFromObj(interp,objv[3],&VALUES[2])!=TCL_OK) return TCL_ERROR;
  14696. if(Tcl_GetDoubleFromObj(interp,objv[4],&VALUES[3])!=TCL_OK) return TCL_ERROR;
  14697. if(Tcl_GetDoubleFromObj(interp,objv[5],&VALUES[4])!=TCL_OK) return TCL_ERROR;
  14698. if(Tcl_GetDoubleFromObj(interp,objv[6],&VALUES[5])!=TCL_OK) return TCL_ERROR;
  14699. }
  14700. pResult=Tcl_NewObj();
  14701. pRow=Tcl_NewObj();
  14702. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14703. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14704. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14705. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14706. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14707. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14708. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14709. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14710. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14711. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14712. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14713. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14714. Tcl_ListObjAppendElement(interp,pResult,pRow);
  14715. pRow=Tcl_NewObj();
  14716. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14717. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14718. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14719. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14720. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14721. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14722. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14723. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14724. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14725. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14726. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14727. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14728. Tcl_ListObjAppendElement(interp,pResult,pRow);
  14729. pRow=Tcl_NewObj();
  14730. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14731. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14732. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14733. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14734. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14735. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14736. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14737. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14738. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14739. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14740. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14741. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14742. Tcl_ListObjAppendElement(interp,pResult,pRow);
  14743. pRow=Tcl_NewObj();
  14744. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14745. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14746. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14747. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14748. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14749. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14750. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14751. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14752. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14753. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14754. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14755. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14756. Tcl_ListObjAppendElement(interp,pResult,pRow);
  14757. pRow=Tcl_NewObj();
  14758. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14759. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14760. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14761. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14762. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14763. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14764. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14765. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14766. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14767. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14768. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MAX_IDX]*scale));
  14769. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14770. Tcl_ListObjAppendElement(interp,pResult,pRow);
  14771. pRow=Tcl_NewObj();
  14772. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14773. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14774. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14775. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14776. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14777. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MAX_IDX]*scale));
  14778. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MIN_IDX]*scale));
  14779. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14780. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14781. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[X_MAX_IDX]*scale));
  14782. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Y_MIN_IDX]*scale));
  14783. Tcl_ListObjAppendElement(interp,pRow,Tcl_NewDoubleObj(VALUES[Z_MIN_IDX]*scale));
  14784. Tcl_ListObjAppendElement(interp,pResult,pRow);
  14785. Tcl_SetObjResult(interp,pResult);
  14786. return TCL_OK;
  14787. }
  14788. /* Tcl Proc ::odie::aabb::from_vectorxyz */
  14789. static int TclCmd_odie_aabb_from_vectorxyz(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14790. MATOBJ *A,*C;
  14791. if( objc < 2 ){
  14792. Tcl_WrongNumArgs(interp, 1, objv, "BBOX\nor\nA B ?C...?");
  14793. return TCL_ERROR;
  14794. }
  14795. if(objc==2) {
  14796. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_aabb_xyz,&C)) return TCL_ERROR;
  14797. VectorXYZ_AABB_Normalize(C->matrix);
  14798. } else {
  14799. int i;
  14800. C=Odie_MatrixObj_Create(MATFORM_aabb_xyz);
  14801. VectorXYZ_AABB_Reset(C->matrix);
  14802. for(i=1;i<objc;i++) {
  14803. if(Odie_GetMatrixFromTclObj(interp,objv[i],MATFORM_vectorxyz,&A)) return TCL_ERROR;
  14804. VectorXYZ_AABB_Measure(A->matrix,C->matrix);
  14805. }
  14806. }
  14807. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  14808. return TCL_OK;
  14809. }
  14810. /* Tcl Proc ::odie::aabb::from_line */
  14811. static int TclCmd_odie_aabb_from_line(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14812. VectorXYZ A,B;
  14813. VectorXYZ AA,BB;
  14814.  
  14815. Tcl_Obj *pResult=Tcl_NewObj();
  14816.  
  14817. if( objc != 3 ){
  14818. Tcl_WrongNumArgs(interp, 1, objv, "A B");
  14819. return TCL_ERROR;
  14820. }
  14821. if(Odie_GetVectorXYZFromTclObj(interp,objv[1],A)) return TCL_ERROR;
  14822. if(Odie_GetVectorXYZFromTclObj(interp,objv[2],B)) return TCL_ERROR;
  14823. AA[X_IDX]=min(A[X_IDX],B[X_IDX]);
  14824. AA[Y_IDX]=min(A[Y_IDX],B[Y_IDX]);
  14825. AA[Z_IDX]=min(A[Z_IDX],B[Z_IDX]);
  14826. BB[X_IDX]=max(A[X_IDX],B[X_IDX]);
  14827. BB[Y_IDX]=max(A[Y_IDX],B[Y_IDX]);
  14828. BB[Z_IDX]=max(A[Z_IDX],B[Z_IDX]);
  14829. pResult=Tcl_NewObj();;
  14830. Tcl_ListObjAppendElement(0, pResult, VectorXYZ_To_TclObj(AA));
  14831. Tcl_ListObjAppendElement(0, pResult, VectorXYZ_To_TclObj(BB));
  14832. Tcl_SetObjResult(interp, pResult);
  14833. return TCL_OK;
  14834. }
  14835. /* Tcl Proc ::odie::aabb::from_center_size */
  14836. static int TclCmd_odie_aabb_from_center_size(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14837. VectorXYZ center,size;
  14838. VectorXYZ AA,BB;
  14839.  
  14840. Tcl_Obj *pResult=Tcl_NewObj();
  14841.  
  14842. if( objc != 3 ){
  14843. Tcl_WrongNumArgs(interp, 1, objv, "center size");
  14844. return TCL_ERROR;
  14845. }
  14846. if(Odie_GetVectorXYZFromTclObj(interp,objv[1],center)) return TCL_ERROR;
  14847. if(Odie_GetVectorXYZFromTclObj(interp,objv[2],size)) return TCL_ERROR;
  14848. size[X_IDX]*=0.5;
  14849. size[Y_IDX]*=0.5;
  14850. size[Z_IDX]*=0.5;
  14851. pResult=Tcl_NewObj();
  14852. VectorXYZ_Subtract(AA,center,size);
  14853. VectorXYZ_Add(BB,center,size);
  14854. Tcl_ListObjAppendElement(0, pResult, VectorXYZ_To_TclObj(AA));
  14855. Tcl_ListObjAppendElement(0, pResult, VectorXYZ_To_TclObj(BB));
  14856. Tcl_SetObjResult(interp, pResult);
  14857. return TCL_OK;
  14858. }
  14859. /* Tcl Proc ::odie::aabb::intersect */
  14860. static int TclCmd_odie_aabb_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14861. MATOBJ *A,*B;
  14862. int c;
  14863. if( objc != 3 ){
  14864. Tcl_WrongNumArgs(interp, 1, objv, "AABB AABB");
  14865. return TCL_ERROR;
  14866. }
  14867. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_aabb_xyz,&A)) return TCL_ERROR;
  14868. if(Odie_GetMatrixFromTclObj(interp,objv[2],MATFORM_aabb_xyz,&B)) return TCL_ERROR;
  14869. c=AABB_AABB_Intersect(A->matrix,B->matrix);
  14870. Tcl_SetObjResult(interp, Tcl_NewIntObj(c));
  14871. return TCL_OK;
  14872. }
  14873. /* Tcl Proc ::odie::aabb::within */
  14874. static int TclCmd_odie_aabb_within(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14875. MATOBJ *A,*B;
  14876. double c;
  14877. if( objc != 3 ){
  14878. Tcl_WrongNumArgs(interp, 1, objv, "AABB POINT");
  14879. return TCL_ERROR;
  14880. }
  14881. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_aabb_xyz,&A)) return TCL_ERROR;
  14882. if(Odie_GetMatrixFromTclObj(interp,objv[2],MATFORM_vectorxyz,&B)) return TCL_ERROR;
  14883. c=VectorXYZ_AABB_Within(B->matrix,A->matrix);
  14884. Tcl_SetObjResult(interp, Tcl_NewIntObj(c));
  14885. return TCL_OK;
  14886. }
  14887. /* Tcl Proc ::affine2d::apply */
  14888. static int TclCmd_affine2d_apply(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14889. Tcl_Obj *pResult=Tcl_NewObj();
  14890. int i;
  14891. double matA[6] = {0.0,0.0,0.0,0.0,0.0,0.0};
  14892.  
  14893. if( objc < 4 ){
  14894. Tcl_WrongNumArgs(interp, 1, objv, "matrix x1 y1 ?x2 y2?...");
  14895. return TCL_ERROR;
  14896. }
  14897. for(i=0;i<6;i++) {
  14898. Tcl_Obj *temp;
  14899. if(Tcl_ListObjIndex(interp, objv[1], i, &temp)) return TCL_ERROR;
  14900. if(Odie_GetMatrixElementFromObj(interp,temp,matA,i)) return TCL_ERROR;
  14901. }
  14902.  
  14903. for(i=2;i<objc;i+=2) {
  14904. double x,y,newx,newy;
  14905. if(Tcl_GetDoubleFromObj(interp,objv[i],&x)) return TCL_ERROR;
  14906. if(Tcl_GetDoubleFromObj(interp,objv[i+1],&y)) return TCL_ERROR;
  14907. newx=matA[0]*x+matA[1]*y+matA[4];
  14908. newy=matA[2]*x+matA[3]*y+matA[5];
  14909. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newx));
  14910. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newy));
  14911. }
  14912. Tcl_SetObjResult(interp, pResult);
  14913. return TCL_OK;
  14914. }
  14915. /* Tcl Proc ::affine2d::combine */
  14916. static int TclCmd_affine2d_combine(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14917. int i,idx;
  14918. Tcl_Obj *pResult=Tcl_NewObj();
  14919. double matA[6] = {0.0,0.0,0.0,0.0,0.0,0.0};
  14920. double matB[6] = {0.0,0.0,0.0,0.0,0.0,0.0};
  14921.  
  14922. if( objc < 2){
  14923. Tcl_WrongNumArgs(interp, 1, objv, "transformA transformB ?transformC?...");
  14924. return TCL_ERROR;
  14925. }
  14926.  
  14927. for(i=0;i<6;i++) {
  14928. Tcl_Obj *temp;
  14929. if(Tcl_ListObjIndex(interp, objv[1], i, &temp)) return TCL_ERROR;
  14930. if(Odie_GetMatrixElementFromObj(interp,temp,matA,i)) return TCL_ERROR;
  14931. }
  14932. for(idx=2;idx<objc;idx++) {
  14933. for(i=0;i<6;i++) {
  14934. Tcl_Obj *temp;
  14935. if(Tcl_ListObjIndex(interp, objv[idx], i, &temp)) return TCL_ERROR;
  14936. if(Odie_GetMatrixElementFromObj(interp,temp,matB,i)) return TCL_ERROR;
  14937. }
  14938. matA[0]=matA[0]*matB[0]+matA[2]*matB[2]; /* [expr {$a*$i+$c*$j}] */
  14939. matA[1]=matA[1]*matB[0]+matA[3]*matB[2]; /* [expr {$b*$i+$d*$j}] */
  14940. matA[2]=matA[0]*matB[2]+matA[2]*matB[3]; /* [expr {$a*$k+$c*$l}] */
  14941. matA[3]=matA[1]*matB[2]+matA[3]*matB[3]; /* [expr {$b*$k+$d*$l}] */
  14942. matA[4]=matA[4]*matB[0]+matA[5]*matB[1]+matB[4]; /* [expr {$e*$i+$f*$j+$m}] */
  14943. matA[5]=matA[4]*matB[2]+matA[5]*matB[3]+matB[5]; /* [expr {$e*$k+$f*$l+$n}]] */
  14944. }
  14945. for(i=0;i<6;i++) {
  14946. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(matA[i]));
  14947. }
  14948. Tcl_SetObjResult(interp, pResult);
  14949. return TCL_OK;
  14950. }
  14951. /* Tcl Proc ::affine2d::rotation_from_angle */
  14952. static int TclCmd_affine2d_rotation_from_angle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14953. Tcl_Obj *pResult=Tcl_NewObj();
  14954. double angle;
  14955. if( (objc != 2) && (objc != 3) ){
  14956. Tcl_WrongNumArgs(interp, 1, objv, "angle ?units?");
  14957. return TCL_ERROR;
  14958. }
  14959. if(Tcl_GetDoubleFromObj(interp,objv[1],&angle)) return TCL_ERROR;
  14960. if(objc==3) {
  14961. /* Scale by the unit */
  14962. char *units;
  14963. units=Tcl_GetString(objv[2]);
  14964. if(units[0]=='d') {
  14965. angle=angle/180.0*M_PI;
  14966. } else if (units[0]=='g') {
  14967. angle=angle/200.0*M_PI;
  14968. } else if (units[0]=='r') {
  14969. } else {
  14970. Tcl_AppendResult(interp, "Unknown unit ", units, " use d[egrees], r[adians], or g[radients]. Radians are assumed",(char*)0);
  14971. return TCL_ERROR;
  14972. }
  14973. }
  14974. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(cos(angle)));
  14975. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(sin(angle)));
  14976. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(-sin(angle)));
  14977. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(cos(angle)));
  14978. Tcl_ListObjAppendElement(interp,pResult,ODIE_REAL_ZERO());
  14979. Tcl_ListObjAppendElement(interp,pResult,ODIE_REAL_ZERO());
  14980. Tcl_SetObjResult(interp, pResult);
  14981. return TCL_OK;
  14982. }
  14983. /* Tcl Proc ::affine2d::rotation_from_normal */
  14984. static int TclCmd_affine2d_rotation_from_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  14985. Tcl_Obj *pResult=Tcl_NewObj();
  14986. double nx,ny,angle;
  14987.  
  14988. if( objc != 3 ){
  14989. Tcl_WrongNumArgs(interp, 1, objv, "nx ny");
  14990. return TCL_ERROR;
  14991. }
  14992. if(Tcl_GetDoubleFromObj(interp,objv[1],&nx)) return TCL_ERROR;
  14993. if(Tcl_GetDoubleFromObj(interp,objv[2],&ny)) return TCL_ERROR;
  14994. angle=atan2(ny,nx);
  14995.  
  14996. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(cos(angle)));
  14997. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(sin(angle)));
  14998. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(-sin(angle)));
  14999. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(cos(angle)));
  15000. Tcl_ListObjAppendElement(interp,pResult,ODIE_REAL_ZERO());
  15001. Tcl_ListObjAppendElement(interp,pResult,ODIE_REAL_ZERO());
  15002. Tcl_SetObjResult(interp, pResult);
  15003. return TCL_OK;
  15004. }
  15005. /* Tcl Proc ::affine4x4::compare */
  15006. static int TclCmd_affine4x4_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15007. Odie_MatrixObj *A,*B;
  15008. int c;
  15009. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_affine,&A)) return TCL_ERROR;
  15010. if(Odie_GetMatrixFromTclObj(interp,objv[2],MATFORM_affine,&B)) return TCL_ERROR;
  15011. c=affine_Compare(A->matrix,B->matrix);
  15012. Tcl_SetObjResult(interp,Tcl_NewBooleanObj(c));
  15013. return TCL_OK;
  15014. }
  15015. /* Tcl Proc ::affine4x4::identity */
  15016. static int TclCmd_affine4x4_identity(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15017. /*
  15018. ** description: Pushes an affine identity matrix onto the stack
  15019. */
  15020. Odie_MatrixObj *C;
  15021. C=Odie_MatrixObj_Create(MATFORM_affine);
  15022. Odie_Affine4x4_Identity(C->matrix);
  15023. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  15024. return TCL_OK;
  15025. }
  15026. /* Tcl Proc ::affine4x4::translation */
  15027. static int TclCmd_affine4x4_translation(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15028. /*
  15029. ** description:
  15030. ** Convert a displacement vector (X Y Z) into an affine transformation
  15031. */
  15032. Odie_MatrixObj *A,*C;
  15033. if(objc != 2) {
  15034. Tcl_WrongNumArgs( interp, 1, objv, "VECTORXYZ" );
  15035. return TCL_ERROR;
  15036. }
  15037. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_vectorxyz,&A)) return TCL_ERROR;
  15038. C=Odie_MatrixObj_Create(MATFORM_affine);
  15039. Odie_Affine4x4_Translation(C->matrix,A->matrix);
  15040. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  15041. return TCL_OK;
  15042. }
  15043. /* Tcl Proc ::affine4x4::scale */
  15044. static int TclCmd_affine4x4_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15045. /*
  15046. ** description:
  15047. ** Convert a scale vector (X Y Z) into an affine transformation
  15048. */
  15049. Odie_MatrixObj *A,*C;
  15050. if(objc != 2) {
  15051. Tcl_WrongNumArgs( interp, 1, objv, "VECTORXYZ" );
  15052. return TCL_ERROR;
  15053. }
  15054. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_vectorxyz,&A)) return TCL_ERROR;
  15055. C=Odie_MatrixObj_Create(MATFORM_affine);
  15056. Odie_Affine4x4_Scale(C->matrix,A->matrix);
  15057. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  15058. return TCL_OK;
  15059. }
  15060. /* Tcl Proc ::affine4x4::rotate_nutation */
  15061. static int TclCmd_affine4x4_rotate_nutation(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15062. double theta;
  15063. Odie_MatrixObj *RESULT;
  15064. if(objc != 2) {
  15065. Tcl_WrongNumArgs( interp, 1, objv, "RADIANS" );
  15066. return TCL_ERROR;
  15067. }
  15068. if(Tcl_GetDoubleFromObj(interp,objv[1],&theta)) return TCL_ERROR;
  15069. RESULT=Odie_MatrixObj_Create(MATFORM_affine);
  15070. affine_rotate_nutation(RESULT->matrix,theta);
  15071. Tcl_SetObjResult(interp,Matrix_To_TclObj(RESULT));
  15072. return TCL_OK;
  15073. }
  15074. /* Tcl Proc ::affine4x4::rotate_precession */
  15075. static int TclCmd_affine4x4_rotate_precession(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15076. double phi;
  15077. Odie_MatrixObj *RESULT;
  15078. Tcl_Obj *pResult;
  15079. if(objc != 2) {
  15080. Tcl_WrongNumArgs( interp, 1, objv, "RADIANS" );
  15081. return TCL_ERROR;
  15082. }
  15083. if(Tcl_GetDoubleFromObj(interp,objv[1],&phi)) return TCL_ERROR;
  15084. RESULT=Odie_MatrixObj_Create(MATFORM_affine);
  15085. affine_rotate_precession(RESULT->matrix,phi);
  15086. Tcl_SetObjResult(interp,Matrix_To_TclObj(RESULT));
  15087. return TCL_OK;
  15088. }
  15089. /* Tcl Proc ::affine4x4::rotate_spin */
  15090. static int TclCmd_affine4x4_rotate_spin(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15091. double psi;
  15092. Odie_MatrixObj *RESULT;
  15093. if(objc != 2) {
  15094. Tcl_WrongNumArgs( interp, 1, objv, "RADIANS" );
  15095. return TCL_ERROR;
  15096. }
  15097. if(Tcl_GetDoubleFromObj(interp,objv[1],&psi)) return TCL_ERROR;
  15098. RESULT=Odie_MatrixObj_Create(MATFORM_affine);
  15099. affine_rotate_spin(RESULT->matrix,psi);
  15100. Tcl_SetObjResult(interp,Matrix_To_TclObj(RESULT));
  15101. return TCL_OK;
  15102. }
  15103. /* Tcl Proc ::affine4x4::from_euler */
  15104. static int TclCmd_affine4x4_from_euler(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15105. /*
  15106. ** description:
  15107. ** Convert a rotation vector (X Y Z) into an affine transformation
  15108. */
  15109. Odie_MatrixObj *A,*C;
  15110. if(objc != 2) {
  15111. Tcl_WrongNumArgs( interp, 1, objv, "EULER" );
  15112. return TCL_ERROR;
  15113. }
  15114. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_euler,&A)) return TCL_ERROR;
  15115. C=Odie_MatrixObj_Create(MATFORM_affine);
  15116. affine_Rotate_From_Euler(C->matrix,A->matrix);
  15117. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  15118. return TCL_OK;
  15119. }
  15120. /* Tcl Proc ::affine4x4::multiply */
  15121. static int TclCmd_affine4x4_multiply(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15122. /*
  15123. ** description:
  15124. ** Multiply 2 4x4 matrices. Used to combine 2 affine transformations.
  15125. ** Note: Some affine transformations need to be performed in a particular
  15126. ** order to make sense.
  15127. */
  15128. Odie_MatrixObj *A,*B,*C;
  15129. if(objc < 3) {
  15130. Tcl_WrongNumArgs( interp, 1, objv, "A B" );
  15131. return TCL_ERROR;
  15132. }
  15133. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_affine,&A)) return TCL_ERROR;
  15134. if(Odie_GetMatrixFromTclObj(interp,objv[2],MATFORM_affine,&B)) return TCL_ERROR;
  15135. C=Odie_MatrixObj_Create(MATFORM_affine);
  15136. Odie_Affine4x4_Multiply(C->matrix,A->matrix,B->matrix);
  15137. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  15138. return TCL_OK;
  15139. }
  15140. /* Tcl Proc ::affine4x4::multiply_inplace */
  15141. static int TclCmd_affine4x4_multiply_inplace(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15142. /*
  15143. ** description:
  15144. ** Multiply 2 4x4 matrices. Used to combine 2 affine transformations.
  15145. ** Note: Some affine transformations need to be performed in a particular
  15146. ** order to make sense.
  15147. */
  15148. Odie_MatrixObj *A,*B,*C;
  15149. Tcl_Obj *varname;
  15150. if(objc < 3) {
  15151. Tcl_WrongNumArgs( interp, 1, objv, "VARNAME AFFINE" );
  15152. return TCL_ERROR;
  15153. }
  15154. Tcl_ResetResult(interp);
  15155. varname=Tcl_ObjGetVar2(interp,objv[1],NULL,0);
  15156. if(Odie_GetMatrixFromTclObj(interp,varname,MATFORM_affine,&A)) return TCL_ERROR;
  15157. if(Odie_GetMatrixFromTclObj(interp,objv[2],MATFORM_affine,&B)) return TCL_ERROR;
  15158. Odie_Affine4x4_Multiply(A->matrix,A->matrix,B->matrix);
  15159. Tcl_InvalidateStringRep(varname);
  15160. return TCL_OK;
  15161. }
  15162. /* Tcl Proc ::affine4x4::inverse */
  15163. static int TclCmd_affine4x4_inverse(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15164. /*
  15165. ** description:
  15166. ** Multiply 2 4x4 matrices. Used to combine 2 affine transformations.
  15167. ** Note: Some affine transformations need to be performed in a particular
  15168. ** order to make sense.
  15169. */
  15170. Odie_MatrixObj *A,*C;
  15171. if(objc < 2) {
  15172. Tcl_WrongNumArgs( interp, 1, objv, "A" );
  15173. return TCL_ERROR;
  15174. }
  15175. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_affine,&A)) return TCL_ERROR;
  15176. C=Odie_MatrixObj_Create(MATFORM_affine);
  15177. Odie_Affine4x4_Inverse(C->matrix,A->matrix);
  15178. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  15179. return TCL_OK;
  15180. }
  15181. /* Tcl Proc ::affine4x4::from_normal */
  15182. static int TclCmd_affine4x4_from_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15183. /*
  15184. ** description:
  15185. ** Convert a displacement normal vector (X Y Z) into an affine transformation
  15186. */
  15187. Odie_MatrixObj *A,*C;
  15188. if(objc != 2) {
  15189. Tcl_WrongNumArgs( interp, 1, objv, "VECTORXYZ" );
  15190. return TCL_ERROR;
  15191. }
  15192. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_vectorxyz,&A)) return TCL_ERROR;
  15193. C=Odie_MatrixObj_Create(MATFORM_affine);
  15194. Odie_Affine_From_Normal(C->matrix,A->matrix);
  15195. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  15196. return TCL_OK;
  15197. }
  15198. /* Tcl Proc ::odie::bbox::create */
  15199. static int TclCmd_odie_bbox_create(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15200. MATOBJ *C;
  15201. C=Odie_MatrixObj_Create(MATFORM_bbox_xy);
  15202. VectorXY_BBOX_Reset(C->matrix);
  15203. if(objc>1) {
  15204. int i;
  15205. VectorXY point;
  15206. for(i=1;i<objc;i++) {
  15207. if(Odie_GetVectorXYFromTclObj(interp,objv[i],point)) return TCL_ERROR;
  15208. VectorXY_BBOX_Measure(point,C->matrix);
  15209. }
  15210. }
  15211. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  15212. return TCL_OK;
  15213. }
  15214. /* Tcl Proc ::odie::bbox::measure */
  15215. static int TclCmd_odie_bbox_measure(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15216. MATOBJ *C;
  15217. Tcl_Obj *varname,*pResult;
  15218. int i;
  15219. VectorXY point;
  15220. if( objc < 3 ){
  15221. Tcl_WrongNumArgs(interp, 1, objv, "BBOX VECTORXY ?VECTORXY..?");
  15222. return TCL_ERROR;
  15223. }
  15224. varname=Tcl_ObjGetVar2(interp,objv[1],NULL,0);
  15225. if(varname) {
  15226. if(Odie_GetMatrixFromTclObj(interp,varname,MATFORM_bbox_xy,&C)) return TCL_ERROR;
  15227. } else {
  15228. C=Odie_MatrixObj_Create(MATFORM_bbox_xy);
  15229. VectorXY_BBOX_Reset(C->matrix);
  15230. }
  15231. for(i=2;i<objc;i++) {
  15232. if(Odie_GetVectorXYFromTclObj(interp,objv[i],point)) return TCL_ERROR;
  15233. VectorXY_BBOX_Measure(point,C->matrix);
  15234. }
  15235. pResult=Matrix_To_TclObj(C);
  15236. Tcl_ObjSetVar2(interp,objv[1],NULL,pResult,0);
  15237. Tcl_SetObjResult(interp,pResult);
  15238. return TCL_OK;
  15239. }
  15240. /* Tcl Proc ::odie::bbox::elements */
  15241. static int TclCmd_odie_bbox_elements(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15242. MATOBJ *C;
  15243. Tcl_Obj *pResult;
  15244. if( objc != 2 ){
  15245. Tcl_WrongNumArgs(interp, 1, objv, "BBOX");
  15246. return TCL_ERROR;
  15247. }
  15248. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_bbox_xy,&C)) return TCL_ERROR;
  15249. pResult=Tcl_NewObj();
  15250. Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(C->matrix[BBOX_X0_IDX]));
  15251. Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(C->matrix[BBOX_Y1_IDX]));
  15252. Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(C->matrix[BBOX_X1_IDX]));
  15253. Tcl_ListObjAppendElement(0, pResult, Tcl_NewDoubleObj(C->matrix[BBOX_Y0_IDX]));
  15254. Tcl_SetObjResult(interp,pResult);
  15255. return TCL_OK;
  15256. }
  15257. /* Tcl Proc ::odie::bbox::intersect */
  15258. static int TclCmd_odie_bbox_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15259. MATOBJ *A,*B;
  15260. int c;
  15261. if( objc != 3 ){
  15262. Tcl_WrongNumArgs(interp, 1, objv, "BBOX BBOX");
  15263. return TCL_ERROR;
  15264. }
  15265. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_bbox_xy,&A)) return TCL_ERROR;
  15266. if(Odie_GetMatrixFromTclObj(interp,objv[2],MATFORM_bbox_xy,&B)) return TCL_ERROR;
  15267. c=BBOX_BBOX_Intersect(A->matrix,B->matrix);
  15268. Tcl_SetObjResult(interp, Tcl_NewIntObj(c));
  15269. return TCL_OK;
  15270. }
  15271. /* Tcl Proc ::odie::bbox::within */
  15272. static int TclCmd_odie_bbox_within(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15273. VectorXY A;
  15274. MATOBJ *C;
  15275. int result;
  15276. if( objc != 3 && objc != 4 ){
  15277. Tcl_WrongNumArgs(interp, 1, objv, "BBOX ?XY| X? ?y?");
  15278. return TCL_ERROR;
  15279. }
  15280. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_bbox_xy,&C)) return TCL_ERROR;
  15281. if(objc==3) {
  15282. if(Odie_GetVectorXYFromTclObj(interp,objv[2],A)) return TCL_ERROR;
  15283. } else {
  15284. double a1,a2;
  15285.  
  15286. if(Tcl_GetDoubleFromObj(interp,objv[2],&a1)) return TCL_ERROR;
  15287. if(Tcl_GetDoubleFromObj(interp,objv[3],&a2)) return TCL_ERROR;
  15288. A[X_IDX]=a1;
  15289. A[Y_IDX]=a2;
  15290. }
  15291. result=VectorXY_Within_BBOX(A,C->matrix);
  15292. Tcl_SetObjResult(interp,Tcl_NewBooleanObj(result));
  15293. return TCL_OK;
  15294. }
  15295. /* Tcl Proc ::quaternion::add */
  15296. static int TclCmd_quaternion_add(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15297. QUATERNION A,B,C;
  15298. if(objc < 3) {
  15299. Tcl_WrongNumArgs( interp, 1, objv, "A B" );
  15300. return TCL_ERROR;
  15301. }
  15302. if(Odie_GetQuaternionFromTclObj(interp,objv[1],A)) return TCL_ERROR;
  15303. if(Odie_GetQuaternionFromTclObj(interp,objv[2],B)) return TCL_ERROR;
  15304. Quaternion_Add(C,A,B);
  15305. Tcl_SetObjResult(interp,Quaternion_To_TclObj(C));
  15306. return TCL_OK;
  15307. }
  15308. /* Tcl Proc ::quaternion::subtract */
  15309. static int TclCmd_quaternion_subtract(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15310. QUATERNION A,B,C;
  15311. if(objc < 3) {
  15312. Tcl_WrongNumArgs( interp, 1, objv, "A B" );
  15313. return TCL_ERROR;
  15314. }
  15315. if(Odie_GetQuaternionFromTclObj(interp,objv[1],A)) return TCL_ERROR;
  15316. if(Odie_GetQuaternionFromTclObj(interp,objv[2],B)) return TCL_ERROR;
  15317. Quaternion_Subtract(C,A,B);
  15318. Tcl_SetObjResult(interp,Quaternion_To_TclObj(C));
  15319. return TCL_OK;
  15320. }
  15321. /* Tcl Proc ::quaternion::multiply */
  15322. static int TclCmd_quaternion_multiply(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15323. QUATERNION A,B,C;
  15324. if(objc < 3) {
  15325. Tcl_WrongNumArgs( interp, 1, objv, "A B" );
  15326. return TCL_ERROR;
  15327. }
  15328. if(Odie_GetQuaternionFromTclObj(interp,objv[1],A)) return TCL_ERROR;
  15329. if(Odie_GetQuaternionFromTclObj(interp,objv[2],B)) return TCL_ERROR;
  15330. Quaternion_Multiply(C,A,B);
  15331. Tcl_SetObjResult(interp,Quaternion_To_TclObj(C));
  15332. return TCL_OK;
  15333. }
  15334. /* Tcl Proc ::quaternion::divide */
  15335. static int TclCmd_quaternion_divide(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15336. QUATERNION A,B,C;
  15337. if(objc < 3) {
  15338. Tcl_WrongNumArgs( interp, 1, objv, "A B" );
  15339. return TCL_ERROR;
  15340. }
  15341. if(Odie_GetQuaternionFromTclObj(interp,objv[1],A)) return TCL_ERROR;
  15342. if(Odie_GetQuaternionFromTclObj(interp,objv[2],B)) return TCL_ERROR;
  15343. Quaternion_Divide(C,A,B);
  15344. Tcl_SetObjResult(interp,Quaternion_To_TclObj(C));
  15345. return TCL_OK;
  15346. }
  15347. /* Tcl Proc ::quaternion::square_root */
  15348. static int TclCmd_quaternion_square_root(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15349. QUATERNION A,C;
  15350. if(objc < 2) {
  15351. Tcl_WrongNumArgs( interp, 1, objv, "A" );
  15352. return TCL_ERROR;
  15353. }
  15354. if(Odie_GetQuaternionFromTclObj(interp,objv[1],A)) return TCL_ERROR;
  15355. Quaternion_Square_Root(C,A);
  15356. Tcl_SetObjResult(interp,Quaternion_To_TclObj(C));
  15357. return TCL_OK;
  15358. }
  15359. /* Tcl Proc ::quaternion::square */
  15360. static int TclCmd_quaternion_square(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15361. QUATERNION A,C;
  15362. if(objc < 2) {
  15363. Tcl_WrongNumArgs( interp, 1, objv, "A" );
  15364. return TCL_ERROR;
  15365. }
  15366. if(Odie_GetQuaternionFromTclObj(interp,objv[1],A)) return TCL_ERROR;
  15367. Quaternion_Square(C,A);
  15368. Tcl_SetObjResult(interp,Quaternion_To_TclObj(C));
  15369. return TCL_OK;
  15370. }
  15371. /* Tcl Proc ::quaternion::from_euler */
  15372. static int TclCmd_quaternion_from_euler(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15373. Odie_MatrixObj *A;
  15374. QUATERNION C;
  15375. if(objc < 2) {
  15376. Tcl_WrongNumArgs( interp, 1, objv, "A" );
  15377. return TCL_ERROR;
  15378. }
  15379. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_euler,&A)) return TCL_ERROR;
  15380. EulerRotation_To_Quaternion(C,A->matrix[EULER_HEADING],A->matrix[EULER_ATTITUDE],A->matrix[EULER_BANK]);
  15381. Tcl_SetObjResult(interp,Quaternion_To_TclObj(C));
  15382. return TCL_OK;
  15383. }
  15384. /* Tcl Proc ::vectorxyz::rotate_by_quaternion */
  15385. static int TclCmd_vectorxyz_rotate_by_quaternion(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15386. QUATERNION A;
  15387. VectorXYZ B,C;
  15388. if(objc < 3) {
  15389. Tcl_WrongNumArgs( interp, 1, objv, "QUATERNION VECTOR ?VECTOR ...?" );
  15390. return TCL_ERROR;
  15391. }
  15392. if(Odie_GetQuaternionFromTclObj(interp,objv[1],A)) return TCL_ERROR;
  15393. if (objc==3) {
  15394. if(Odie_GetVectorXYZFromTclObj(interp,objv[2],B)) return TCL_ERROR;
  15395. VectorXYZ_Rotate_by_Quaternion(C,A,B);
  15396. Tcl_SetObjResult(interp,VectorXYZ_To_TclObj(C));
  15397. } else {
  15398. Tcl_Obj *pResult=Tcl_NewObj();
  15399. int i;
  15400. for(i=2;i<objc;i++) {
  15401. if(Odie_GetVectorXYZFromTclObj(interp,objv[i],B)) return TCL_ERROR;
  15402. VectorXYZ_Rotate_by_Quaternion(C,A,B);
  15403. Tcl_ListObjAppendElement(interp,pResult,VectorXYZ_To_TclObj(C));
  15404. }
  15405. Tcl_SetObjResult(interp,pResult);
  15406. }
  15407. return TCL_OK;
  15408. }
  15409. /* Tcl Proc ::quaternion::to_euler */
  15410. static int TclCmd_quaternion_to_euler(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15411. QUATERNION A;
  15412. VectorXYZ C;
  15413. Odie_MatrixObj *RESULT;
  15414. if(objc < 2) {
  15415. Tcl_WrongNumArgs( interp, 1, objv, "A" );
  15416. return TCL_ERROR;
  15417. }
  15418. if(Odie_GetQuaternionFromTclObj(interp,objv[1],A)) return TCL_ERROR;
  15419. Quaternion_To_EulerRotation(C,A);
  15420. RESULT=Odie_MatrixObj_Create(MATFORM_euler);
  15421. RESULT->matrix[X_IDX]=A[X_IDX];
  15422. RESULT->matrix[Y_IDX]=A[Y_IDX];
  15423. RESULT->matrix[Z_IDX]=A[Z_IDX];
  15424. Tcl_SetObjResult(interp,Matrix_To_TclObj(RESULT));
  15425. return TCL_OK;
  15426. }
  15427. /* Tcl Proc ::quaternion::from_normal */
  15428. static int TclCmd_quaternion_from_normal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15429. VectorXYZ FROM,TO;
  15430. Odie_MatrixObj *RESULT;
  15431. if(objc != 2 && objc !=3) {
  15432. Tcl_WrongNumArgs( interp, 1, objv, "?FROM? TO" );
  15433. return TCL_ERROR;
  15434. }
  15435. if(objc==2) {
  15436. FROM[X_IDX]=0.0;
  15437. FROM[Y_IDX]=0.0;
  15438. FROM[Z_IDX]=-1.0;
  15439. if(Odie_GetVectorXYZFromTclObj(interp,objv[1],TO)) return TCL_ERROR;
  15440. } else {
  15441. if(Odie_GetVectorXYZFromTclObj(interp,objv[1],FROM)) return TCL_ERROR;
  15442. if(Odie_GetVectorXYZFromTclObj(interp,objv[2],TO)) return TCL_ERROR;
  15443. }
  15444. RESULT=Odie_MatrixObj_Create(MATFORM_quaternion);
  15445. Quaternion_From_Normal(RESULT->matrix,FROM,TO);
  15446. Tcl_SetObjResult(interp,Matrix_To_TclObj(RESULT));
  15447. return TCL_OK;
  15448. }
  15449. /* Tcl Proc ::odie::tolerance */
  15450. static int TclCmd_odie_tolerance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15451. if(objc==2) {
  15452. double newval;
  15453. if(Tcl_GetDoubleFromObj(interp,objv[1],&newval)) return TCL_ERROR;
  15454. Vector_Set_Tolerance(newval);
  15455. }
  15456. Tcl_SetObjResult(interp,Tcl_NewDoubleObj(Vector_Tolerance));
  15457. return TCL_OK;
  15458. }
  15459. /* Tcl Proc ::odie::vector::to_list */
  15460. static int TclCmd_odie_vector_to_list(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15461. Odie_MatrixObj *A;
  15462. int idx;
  15463. int size_a;
  15464. if(objc != 2) {
  15465. Tcl_WrongNumArgs( interp, 1, objv, "A" );
  15466. return TCL_ERROR;
  15467. }
  15468. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15469. size_a=A->rows*A->cols;
  15470. Tcl_Obj **pList=NULL;
  15471.  
  15472. pList=Odie_Alloc(sizeof(Tcl_Obj)*size_a);
  15473. for(idx=0;idx<size_a;idx++) {
  15474. pList[idx]=Tcl_NewDoubleObj(*(A->matrix+idx));
  15475. }
  15476. Tcl_SetObjResult(interp,Tcl_NewListObj(size_a,pList));
  15477. return TCL_OK;
  15478. }
  15479. /* Tcl Proc ::odie::vector::index */
  15480. static int TclCmd_odie_vector_index(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15481. Odie_MatrixObj *A;
  15482. int i=-1,j=-1,idx,n=0;
  15483. int size_a;
  15484. Tcl_Obj **pList=NULL;
  15485.  
  15486. if(objc != 3 && objc != 4) {
  15487. Tcl_WrongNumArgs( interp, 1, objv, "A i ?j?" );
  15488. return TCL_ERROR;
  15489. }
  15490. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15491. if(Tcl_GetIntFromObj(interp,objv[2],&i)) return TCL_ERROR;
  15492. size_a=A->rows*A->cols;
  15493.  
  15494. if(i<0) {
  15495. i=0;
  15496. }
  15497. if(i>=size_a) {
  15498. i=size_a-1;
  15499. }
  15500. if(objc==3) {
  15501. j=i;
  15502. } else{
  15503. if(Tcl_GetIntFromObj(interp,objv[3],&j)) return TCL_ERROR;
  15504. }
  15505. if ( j < 0 ) {
  15506. j=size_a-1;
  15507. } else if (j<=i) {
  15508. Tcl_SetObjResult(interp,Tcl_NewDoubleObj(*(A->matrix+i)));
  15509. return TCL_OK;
  15510. }
  15511. if(j>=size_a) {
  15512. j=size_a-1;
  15513. }
  15514. n=(j-i)+1;
  15515. pList=Odie_Alloc(sizeof(Tcl_Obj)*n);
  15516. for(idx=i;idx<=j;idx++) {
  15517. pList[idx]=Tcl_NewDoubleObj(*(A->matrix+idx));
  15518. }
  15519. Tcl_SetObjResult(interp,Tcl_NewListObj(n,pList));
  15520. return TCL_OK;
  15521. }
  15522. /* Tcl Proc ::odie::vector::add */
  15523. static int TclCmd_odie_vector_add(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15524. Odie_MatrixObj *A,*B,*C;
  15525. int i,size_c;
  15526. if(objc < 3) {
  15527. Tcl_WrongNumArgs( interp, 1, objv, "A B" );
  15528. return TCL_ERROR;
  15529. }
  15530. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15531. if(Odie_GetMatrixFromTclObj(interp,objv[2],MATFORM_null,&B)) return TCL_ERROR;
  15532. C=Odie_Matrix_To_Fit(A,B);
  15533. size_c=C->rows*C->cols;
  15534. for(i=0;i<size_c;i++) {
  15535. *(C->matrix+i) = *(A->matrix+i) + *(B->matrix+i);
  15536. }
  15537. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  15538. return TCL_OK;
  15539. }
  15540. /* Tcl Proc ::odie::vector::is_null */
  15541. static int TclCmd_odie_vector_is_null(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15542. Odie_MatrixObj *A,*B,*C;
  15543. int i,size_c;
  15544. if(objc < 2) {
  15545. Tcl_WrongNumArgs( interp, 1, objv, "VECTOR" );
  15546. return TCL_ERROR;
  15547. }
  15548. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) {
  15549. Tcl_ResetResult(interp);
  15550. Tcl_SetObjResult(interp,Tcl_NewBooleanObj(1));
  15551. return TCL_OK;
  15552. }
  15553. int size=A->rows*A->cols;
  15554. if(size<2) {
  15555. Tcl_SetObjResult(interp,Tcl_NewBooleanObj(1));
  15556. return TCL_OK;
  15557. } else {
  15558. Tcl_SetObjResult(interp,Tcl_NewBooleanObj(0));
  15559. }
  15560. return TCL_OK;
  15561. }
  15562. /* Tcl Proc ::odie::vector::subtract */
  15563. static int TclCmd_odie_vector_subtract(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15564. Odie_MatrixObj *A,*B,*C;
  15565. int i,size_c;
  15566. if(objc < 3) {
  15567. Tcl_WrongNumArgs( interp, 1, objv, "A B" );
  15568. return TCL_ERROR;
  15569. }
  15570. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15571. if(Odie_GetMatrixFromTclObj(interp,objv[2],MATFORM_null,&B)) return TCL_ERROR;
  15572. C=Odie_Matrix_To_Fit(A,B);
  15573. size_c=C->rows*C->cols;
  15574. for(i=0;i<size_c;i++) {
  15575. *(C->matrix+i) = *(A->matrix+i) - *(B->matrix+i);
  15576. }
  15577. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  15578. return TCL_OK;
  15579. }
  15580. /* Tcl Proc ::odie::vector::midpoint */
  15581. static int TclCmd_odie_vector_midpoint(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15582. Odie_MatrixObj *A,*B,*C;
  15583. int i,size_c;
  15584. if(objc < 3) {
  15585. Tcl_WrongNumArgs( interp, 1, objv, "A B" );
  15586. return TCL_ERROR;
  15587. }
  15588. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15589. if(Odie_GetMatrixFromTclObj(interp,objv[2],MATFORM_null,&B)) return TCL_ERROR;
  15590. C=Odie_Matrix_To_Fit(A,B);
  15591. size_c=C->rows*C->cols;
  15592. for(i=0;i<size_c;i++) {
  15593. *(C->matrix+i) = (*(A->matrix+i) - *(B->matrix+i))*0.5 + *(A->matrix+i);
  15594. }
  15595. Tcl_SetObjResult(interp,Matrix_To_TclObj(C));
  15596. return TCL_OK;
  15597. }
  15598. /* Tcl Proc ::odie::vector::reciprocal */
  15599. static int TclCmd_odie_vector_reciprocal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15600. Odie_MatrixObj *A,*RESULT;
  15601. int i;
  15602. int size_a;
  15603. if(objc != 2) {
  15604. Tcl_WrongNumArgs( interp, 1, objv, "A" );
  15605. return TCL_ERROR;
  15606. }
  15607. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15608. RESULT=Odie_Matrix_To_Fit(A,A);
  15609. size_a=A->rows*A->cols;
  15610. for(i=0;i<size_a;i++) {
  15611. *(RESULT->matrix+i) = 1.0 / *(A->matrix+i);
  15612. }
  15613. Tcl_SetObjResult(interp,Matrix_To_TclObj(RESULT));
  15614. return TCL_OK;
  15615. }
  15616. /* Tcl Proc ::odie::vector::dot_product */
  15617. static int TclCmd_odie_vector_dot_product(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15618. Odie_MatrixObj *A,*B;
  15619. int i;
  15620. int size_a;
  15621. int size_b;
  15622. if(objc < 3) {
  15623. Tcl_WrongNumArgs( interp, 1, objv, "A B" );
  15624. return TCL_ERROR;
  15625. }
  15626. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15627. if(Odie_GetMatrixFromTclObj(interp,objv[2],MATFORM_null,&B)) return TCL_ERROR;
  15628. size_a=A->rows*A->cols;
  15629. size_b=B->rows*B->cols;
  15630. double result=0;
  15631. for(i=0;i<size_a && i<size_b;i++) {
  15632. result += *(A->matrix+i) * *(B->matrix+i);
  15633. }
  15634. Tcl_SetObjResult(interp,Tcl_NewDoubleObj(result));
  15635. return TCL_OK;
  15636. }
  15637. /* Tcl Proc ::odie::vector::to_matrix */
  15638. static int TclCmd_odie_vector_to_matrix(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15639. Odie_MatrixObj *A;
  15640. if(objc < 2) {
  15641. Tcl_WrongNumArgs( interp, 1, objv, "A" );
  15642. return TCL_ERROR;
  15643. }
  15644. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15645. Tcl_SetObjResult(interp,Matrix_To_TclObj(A));
  15646. return TCL_OK;
  15647. }
  15648. /* Tcl Proc ::odie::vector::to_fuzzy */
  15649. static int TclCmd_odie_vector_to_fuzzy(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15650. Odie_MatrixObj *A;
  15651. int i,size_a;
  15652. Tcl_Obj *pResult;
  15653. if(objc < 2) {
  15654. Tcl_WrongNumArgs( interp, 1, objv, "A" );
  15655. return TCL_ERROR;
  15656. }
  15657. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15658. pResult=Tcl_NewObj();
  15659. size_a=A->rows*A->cols;
  15660. for(i=0;i<size_a;i++) {
  15661. Tcl_ListObjAppendElement(interp,pResult,ODIE_NewFuzzyObj(*(A->matrix+i)));
  15662. }
  15663. Tcl_SetObjResult(interp,pResult);
  15664. return TCL_OK;
  15665. }
  15666. /* Tcl Proc ::odie::vector::scale */
  15667. static int TclCmd_odie_vector_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15668. Odie_MatrixObj *A,*B,*C=NULL,*RESULT;
  15669. int i,size_a,size_b,size_c;
  15670. if(objc!=3 && objc !=4) {
  15671. Tcl_WrongNumArgs( interp, 1, objv, "A SCALE ?TRANSLATE?" );
  15672. return TCL_ERROR;
  15673. }
  15674. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15675. if(Odie_GetMatrixFromTclObj(interp,objv[2],MATFORM_null,&B)) return TCL_ERROR;
  15676. size_a=A->rows*A->cols;
  15677. size_b=B->rows*B->cols;
  15678. if(size_b > 1 && size_b!=size_a) {
  15679. Tcl_AppendResult(interp, "B is not a scaler, or arguments are not of the same size", 0);
  15680. return TCL_ERROR;
  15681. }
  15682.  
  15683. if(objc==4) {
  15684. if(Odie_GetMatrixFromTclObj(interp,objv[3],MATFORM_null,&C)) return TCL_ERROR;
  15685. size_c=C->rows*C->cols;
  15686. if(size_c!=size_a) {
  15687. Tcl_AppendResult(interp, "TRANS is not the same size", 0);
  15688. return TCL_ERROR;
  15689. }
  15690. }
  15691. RESULT=Odie_Matrix_Duplicate(A);
  15692. if(size_b==1) {
  15693. double scaler=*(B->matrix+0);
  15694. for(i=0;i<size_a;i++) {
  15695. *(RESULT->matrix+i) *= scaler;
  15696. }
  15697. } else {
  15698. for(i=0;i<size_a;i++) {
  15699. *(RESULT->matrix+i) *= *(B->matrix+i);
  15700. }
  15701. }
  15702. if(C) {
  15703. for(i=0;i<size_a;i++) {
  15704. *(RESULT->matrix+i) -= *(C->matrix+i);
  15705. }
  15706. }
  15707.  
  15708. Tcl_SetObjResult(interp,Matrix_To_TclObj(RESULT));
  15709. return TCL_OK;
  15710. }
  15711. /* Tcl Proc ::odie::vector::length */
  15712. static int TclCmd_odie_vector_length(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15713. int i,size;
  15714. Odie_MatrixObj *A;
  15715. double result,sum=0.0;
  15716. if( objc!=2 ){
  15717. Tcl_WrongNumArgs(interp, 1, objv, "vector");
  15718. return TCL_ERROR;
  15719. }
  15720. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15721. size=A->rows*A->cols;
  15722. result=0.0;
  15723. for(i=1;i<size;i++) {
  15724. double a=*(A->matrix+1);
  15725. sum+=a*a;
  15726. }
  15727. result=sqrt(sum);
  15728. Tcl_SetObjResult(interp,Tcl_NewDoubleObj(result));
  15729. return TCL_OK;
  15730. }
  15731. /* Tcl Proc ::odie::vector::length_squared */
  15732. static int TclCmd_odie_vector_length_squared(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15733. int i,size;
  15734. Odie_MatrixObj *A;
  15735. double result,sum=0.0;
  15736. if( objc!=2 ){
  15737. Tcl_WrongNumArgs(interp, 1, objv, "vector");
  15738. return TCL_ERROR;
  15739. }
  15740. if(Odie_GetMatrixFromTclObj(interp,objv[1],MATFORM_null,&A)) return TCL_ERROR;
  15741. size=A->rows*A->cols;
  15742. result=0.0;
  15743. for(i=1;i<size;i++) {
  15744. double a=*(A->matrix+1);
  15745. sum+=a*a;
  15746. }
  15747. result=sum;
  15748. Tcl_SetObjResult(interp,Tcl_NewDoubleObj(result));
  15749. return TCL_OK;
  15750. }
  15751. /* Tcl Proc ::odie::grid */
  15752. static int TclCmd_odie_grid(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15753. double grid,grain;
  15754. int gridint,i,asint=0;
  15755. Tcl_Obj *pResult;
  15756. if( objc < 3 ){
  15757. Tcl_WrongNumArgs(interp, 1, objv, "grid DBL ...");
  15758. return TCL_ERROR;
  15759. }
  15760. asint=1;
  15761. if(Tcl_GetIntFromObj(interp,objv[1],&gridint)) {
  15762. asint=0;
  15763. if(Tcl_GetDoubleFromObj(interp,objv[1],&grid)) return TCL_ERROR;
  15764. } else {
  15765. grid=(double)gridint;
  15766. }
  15767. pResult=Tcl_NewObj();
  15768. grain=grid*0.5;
  15769. for(i=2;i<objc;i++) {
  15770. double thisval,remainder;
  15771. if(Tcl_GetDoubleFromObj(interp,objv[i],&thisval)) {
  15772. Tcl_DecrRefCount(pResult);
  15773. return TCL_ERROR;
  15774. }
  15775. thisval=Vector_GridScaler(thisval,grid,grain);
  15776. if(asint) {
  15777. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewIntObj(thisval));
  15778. } else {
  15779. remainder=fmod(thisval,grid);
  15780. Tcl_ListObjAppendElement(interp, pResult, ODIE_NewFuzzyObj(thisval-remainder));
  15781. }
  15782. }
  15783. Tcl_SetObjResult(interp, pResult);
  15784. return TCL_OK;
  15785. }
  15786. /* Tcl Proc ::odie::gridvar */
  15787. static int TclCmd_odie_gridvar(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15788. double grid,grain,val;
  15789. int gridint,i,asint=0;
  15790. if( objc < 3 ){
  15791. Tcl_WrongNumArgs(interp, 1, objv, "gridsize DBLVAR ...");
  15792. return TCL_ERROR;
  15793. }
  15794. asint=1;
  15795. if(Tcl_GetIntFromObj(interp,objv[1],&gridint)) {
  15796. asint=0;
  15797. if(Tcl_GetDoubleFromObj(interp,objv[1],&grid)) return TCL_ERROR;
  15798. } else {
  15799. grid=(double)gridint;
  15800. }
  15801. grain=grid*0.5;
  15802. for(i=2;i<objc;i++) {
  15803. double thisval,remainder;
  15804. Tcl_Obj *varname;
  15805. varname=Tcl_ObjGetVar2(interp,objv[i],NULL,0);
  15806. if(varname==NULL) continue;
  15807. if(Tcl_GetDoubleFromObj(interp,varname,&val)) continue;
  15808. thisval=Vector_GridScaler(val,grid,grain);
  15809. if(asint) {
  15810. Tcl_ObjSetVar2(interp,objv[i],NULL,Tcl_NewIntObj(thisval),0);
  15811. } else {
  15812. remainder=fmod(thisval,grid);
  15813. Tcl_ObjSetVar2(interp,objv[i],NULL,ODIE_NewFuzzyObj(thisval-remainder),0);
  15814. }
  15815. }
  15816. return TCL_OK;
  15817. }
  15818. /* Tcl Proc ::vector2d::compare */
  15819. static int TclCmd_vector2d_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15820. VectorXY A, B;
  15821. int c;
  15822. if( objc!=5 ){
  15823. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 X1 Y1");
  15824. return TCL_ERROR;
  15825. }
  15826. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  15827. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  15828. if( Odie_GetMatrixElementFromObj(interp, objv[3], B, X_IDX) ) return TCL_ERROR;
  15829. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, Y_IDX) ) return TCL_ERROR;
  15830. c=VectorXY_SamePoint(A,B);
  15831. Tcl_SetObjResult(interp, Tcl_NewBooleanObj(c));
  15832. return TCL_OK;
  15833. }
  15834. /* Tcl Proc ::vector2d::add */
  15835. static int TclCmd_vector2d_add(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15836. VectorXY A, B, P;
  15837. Tcl_Obj *pResult;
  15838. if( objc!=5 ){
  15839. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 X1 Y1");
  15840. return TCL_ERROR;
  15841. }
  15842. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  15843. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  15844. if( Odie_GetMatrixElementFromObj(interp, objv[3], B, X_IDX) ) return TCL_ERROR;
  15845. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, Y_IDX) ) return TCL_ERROR;
  15846. VectorXY_Add(P,A,B);
  15847. pResult=Tcl_NewObj();
  15848. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[X_IDX]));
  15849. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[Y_IDX]));
  15850. Tcl_SetObjResult(interp, pResult);
  15851. return TCL_OK;
  15852. }
  15853. /* Tcl Proc ::vector2d::subtract */
  15854. static int TclCmd_vector2d_subtract(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15855. VectorXY A, B, P;
  15856. Tcl_Obj *pResult;
  15857. if( objc!=5 ){
  15858. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 X1 Y1");
  15859. return TCL_ERROR;
  15860. }
  15861. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  15862. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  15863. if( Odie_GetMatrixElementFromObj(interp, objv[3], B, X_IDX) ) return TCL_ERROR;
  15864. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, Y_IDX) ) return TCL_ERROR;
  15865. VectorXY_Subtract(P,A,B);
  15866. pResult=Tcl_NewObj();
  15867. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[X_IDX]));
  15868. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[Y_IDX]));
  15869. Tcl_SetObjResult(interp, pResult);
  15870. return TCL_OK;
  15871. }
  15872. /* Tcl Proc ::vector2d::midpoint */
  15873. static int TclCmd_vector2d_midpoint(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15874. VectorXY A, B, P;
  15875. Tcl_Obj *pResult;
  15876. if( objc!=5 ){
  15877. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 X1 Y1");
  15878. return TCL_ERROR;
  15879. }
  15880. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  15881. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  15882. if( Odie_GetMatrixElementFromObj(interp, objv[3], B, X_IDX) ) return TCL_ERROR;
  15883. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, Y_IDX) ) return TCL_ERROR;
  15884. VectorXY_Midpoint(P,A,B);
  15885. pResult=Tcl_NewObj();
  15886. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[X_IDX]));
  15887. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[Y_IDX]));
  15888. Tcl_SetObjResult(interp, pResult);
  15889. return TCL_OK;
  15890. }
  15891. /* Tcl Proc ::vector2d::affine_apply */
  15892. static int TclCmd_vector2d_affine_apply(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15893. Tcl_Obj *pResult;
  15894. int i;
  15895. double matA[6] = {0.0,0.0,0.0,0.0,0.0,0.0};
  15896.  
  15897. if( objc < 4 ){
  15898. Tcl_WrongNumArgs(interp, 1, objv, "matrix x1 y1 ?x2 y2?...");
  15899. return TCL_ERROR;
  15900. }
  15901. for(i=0;i<6;i++) {
  15902. Tcl_Obj *temp;
  15903. if(Tcl_ListObjIndex(interp, objv[1], i, &temp)) return TCL_ERROR;
  15904. if(Odie_GetMatrixElementFromObj(interp,temp,matA,i)) return TCL_ERROR;
  15905. }
  15906. pResult=Tcl_NewObj();
  15907. for(i=2;i<objc;i+=2) {
  15908. double x,y,newx,newy;
  15909. if(Tcl_GetDoubleFromObj(interp,objv[i],&x)) {
  15910. Tcl_DecrRefCount(pResult);
  15911. return TCL_ERROR;
  15912. }
  15913. if(Tcl_GetDoubleFromObj(interp,objv[i+1],&y)) {
  15914. Tcl_DecrRefCount(pResult);
  15915. return TCL_ERROR;
  15916. }
  15917. newx=matA[0]*x+matA[1]*y+matA[4];
  15918. newy=matA[2]*x+matA[3]*y+matA[5];
  15919. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newx));
  15920. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newy));
  15921. }
  15922. Tcl_SetObjResult(interp, pResult);
  15923. return TCL_OK;
  15924. }
  15925. /* Tcl Proc ::vector2d::angle */
  15926. static int TclCmd_vector2d_angle(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15927. VectorXY A, B, P;
  15928. if( objc!=7 ){
  15929. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 X1 Y1 X2 Y2");
  15930. return TCL_ERROR;
  15931. }
  15932. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  15933. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  15934. if( Odie_GetMatrixElementFromObj(interp, objv[3], B, X_IDX) ) return TCL_ERROR;
  15935. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, Y_IDX) ) return TCL_ERROR;
  15936. if( Odie_GetMatrixElementFromObj(interp, objv[5], P, X_IDX) ) return TCL_ERROR;
  15937. if( Odie_GetMatrixElementFromObj(interp, objv[6], P, Y_IDX) ) return TCL_ERROR;
  15938. Tcl_SetObjResult(interp, Tcl_NewDoubleObj(VectorXY_Angle_Three_Point(A, B, P)));
  15939. return TCL_OK;
  15940. }
  15941. /* Tcl Proc ::vector2d::distance */
  15942. static int TclCmd_vector2d_distance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15943. double result,ax,ay,bx,by,dx,dy;
  15944. if( objc!=5 ){
  15945. Tcl_WrongNumArgs(interp, 1, objv, "x0 y0 x1 y1");
  15946. return TCL_ERROR;
  15947. }
  15948. result=0.0;
  15949. if(Tcl_GetDoubleFromObj(interp,objv[1],&ax)) return TCL_ERROR;
  15950. if(Tcl_GetDoubleFromObj(interp,objv[2],&ay)) return TCL_ERROR;
  15951. if(Tcl_GetDoubleFromObj(interp,objv[3],&bx)) return TCL_ERROR;
  15952. if(Tcl_GetDoubleFromObj(interp,objv[4],&by)) return TCL_ERROR;
  15953. dx=bx-ax;
  15954. dy=by-ay;
  15955.  
  15956. result=sqrt(dx*dx + dy*dy);
  15957. Tcl_SetObjResult(interp,Tcl_NewDoubleObj(result));
  15958. return TCL_OK;
  15959. }
  15960. /* Tcl Proc ::vector2d::dotproduct */
  15961. static int TclCmd_vector2d_dotproduct(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15962. VectorXY A, B, P;
  15963. if( objc!=7 ){
  15964. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 X1 Y1 X2 Y2");
  15965. return TCL_ERROR;
  15966. }
  15967. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  15968. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  15969. if( Odie_GetMatrixElementFromObj(interp, objv[3], B, X_IDX) ) return TCL_ERROR;
  15970. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, Y_IDX) ) return TCL_ERROR;
  15971. if( Odie_GetMatrixElementFromObj(interp, objv[5], P, X_IDX) ) return TCL_ERROR;
  15972. if( Odie_GetMatrixElementFromObj(interp, objv[6], P, Y_IDX) ) return TCL_ERROR;
  15973. Tcl_SetObjResult(interp, Tcl_NewDoubleObj(VectorXY_Dot_Product(A, B, P)));
  15974. return TCL_OK;
  15975. }
  15976. /* Tcl Proc ::vector2d::crossproduct */
  15977. static int TclCmd_vector2d_crossproduct(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15978. VectorXY A, B, P;
  15979. if( objc!=7 ){
  15980. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 X1 Y1 X2 Y2");
  15981. return TCL_ERROR;
  15982. }
  15983. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  15984. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  15985. if( Odie_GetMatrixElementFromObj(interp, objv[3], B, X_IDX) ) return TCL_ERROR;
  15986. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, Y_IDX) ) return TCL_ERROR;
  15987. if( Odie_GetMatrixElementFromObj(interp, objv[5], P, X_IDX) ) return TCL_ERROR;
  15988. if( Odie_GetMatrixElementFromObj(interp, objv[6], P, Y_IDX) ) return TCL_ERROR;
  15989. Tcl_SetObjResult(interp, Tcl_NewDoubleObj(VectorXY_crossProduct(A, B, P)));
  15990. return TCL_OK;
  15991. }
  15992. /* Tcl Proc ::vector2d::rightof */
  15993. static int TclCmd_vector2d_rightof(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  15994. /*
  15995. ** tclcmd: triag_test_rightof X0 Y0 X1 Y1 X2 Y2
  15996. **
  15997. ** A TCL command for testing the rightOf() function.
  15998. */
  15999. VectorXY A, B, P;
  16000. if( objc!=7 ){
  16001. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 X1 Y1 X2 Y2");
  16002. return TCL_ERROR;
  16003. }
  16004. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  16005. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  16006. if( Odie_GetMatrixElementFromObj(interp, objv[3], B, X_IDX) ) return TCL_ERROR;
  16007. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, Y_IDX) ) return TCL_ERROR;
  16008. if( Odie_GetMatrixElementFromObj(interp, objv[5], P, X_IDX) ) return TCL_ERROR;
  16009. if( Odie_GetMatrixElementFromObj(interp, objv[6], P, Y_IDX) ) return TCL_ERROR;
  16010. Tcl_SetObjResult(interp, Tcl_NewIntObj(VectorXY_BendDirection(A, B, P)));
  16011. return TCL_OK;
  16012. }
  16013. /* Tcl Proc ::vector2d::rotate_and_size */
  16014. static int TclCmd_vector2d_rotate_and_size(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16015. /*
  16016. ** Apply Matrices
  16017. */
  16018. Tcl_Obj *pResult;
  16019. int i;
  16020. double matA[6] = {1.0,0.0,0.0,1.0,0.0,0.0};
  16021. double nx,ny,scalex,scaley,angle;
  16022.  
  16023. if( objc < 7 ){
  16024. Tcl_WrongNumArgs(interp, 1, objv, "normalx normaly sizex sizey x1 y1 ?x2 y2?...");
  16025. return TCL_ERROR;
  16026. }
  16027.  
  16028. if(Tcl_GetDoubleFromObj(interp,objv[1],&nx)) return TCL_ERROR;
  16029. if(Tcl_GetDoubleFromObj(interp,objv[2],&ny)) return TCL_ERROR;
  16030. if(Tcl_GetDoubleFromObj(interp,objv[3],&scalex)) return TCL_ERROR;
  16031. if(Tcl_GetDoubleFromObj(interp,objv[4],&scaley)) return TCL_ERROR;
  16032.  
  16033. angle=atan2(ny,nx);
  16034. matA[0]=cos(angle);
  16035. matA[1]=sin(angle);
  16036. matA[2]=-sin(angle);
  16037. matA[3]=cos(angle);
  16038. matA[4]=0.0;
  16039. matA[5]=0.0;
  16040.  
  16041. scalex*=0.5;
  16042. scaley*=0.5;
  16043. pResult=Tcl_NewObj();
  16044. for(i=5;i<objc;i+=2) {
  16045. double x,y,sx,sy,newx,newy;
  16046. if(Tcl_GetDoubleFromObj(interp,objv[i],&x)) {
  16047. Tcl_DecrRefCount(pResult);
  16048. return TCL_ERROR;
  16049. }
  16050. if(Tcl_GetDoubleFromObj(interp,objv[i+1],&y)) {
  16051. Tcl_DecrRefCount(pResult);
  16052. return TCL_ERROR;
  16053. }
  16054. sx=x*scalex;
  16055. sy=y*scaley;
  16056. newx=matA[0]*sx+matA[1]*sy+matA[4];
  16057. newy=matA[2]*sx+matA[3]*sy+matA[5];
  16058.  
  16059. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newx));
  16060. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newy));
  16061. }
  16062. Tcl_SetObjResult(interp, pResult);
  16063. return TCL_OK;
  16064. }
  16065. /* Tcl Proc ::vector2d::scale */
  16066. static int TclCmd_vector2d_scale(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16067. Tcl_Obj *pResult;
  16068. int i;
  16069. double scalex,scaley;
  16070.  
  16071. if( objc < 5 ){
  16072. Tcl_WrongNumArgs(interp, 1, objv, "sizex sizey x1 y1 ?x2 y2?...");
  16073. return TCL_ERROR;
  16074. }
  16075.  
  16076. if(Tcl_GetDoubleFromObj(interp,objv[1],&scalex)) return TCL_ERROR;
  16077. if(Tcl_GetDoubleFromObj(interp,objv[2],&scaley)) return TCL_ERROR;
  16078. pResult=Tcl_NewObj();
  16079. scalex*=0.5;
  16080. scaley*=0.5;
  16081. for(i=3;i<objc;i+=2) {
  16082. double x,y,sx,sy;
  16083. if(Tcl_GetDoubleFromObj(interp,objv[i],&x)) {
  16084. Tcl_DecrRefCount(pResult);
  16085. return TCL_ERROR;
  16086. }
  16087. if(Tcl_GetDoubleFromObj(interp,objv[i+1],&y)) {
  16088. Tcl_DecrRefCount(pResult);
  16089. return TCL_ERROR;
  16090. }
  16091. sx=x*scalex;
  16092. sy=y*scaley;
  16093. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(sx));
  16094. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(sy));
  16095. }
  16096. Tcl_SetObjResult(interp, pResult);
  16097. return TCL_OK;
  16098. }
  16099. /* Tcl Proc ::vector2d::translate_and_zoom */
  16100. static int TclCmd_vector2d_translate_and_zoom(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16101. /*
  16102. ** Apply Matrices
  16103. */
  16104. Tcl_Obj *pResult;
  16105. int i;
  16106. double zoom;
  16107. double centerx,centery;
  16108.  
  16109. if( objc < 6 ){
  16110. Tcl_WrongNumArgs(interp, 1, objv, "zoom centerx centery x1 y1 ?x2 y2?...");
  16111. return TCL_ERROR;
  16112. }
  16113. if(Tcl_GetDoubleFromObj(interp,objv[1],&zoom)) return TCL_ERROR;
  16114. if(Tcl_GetDoubleFromObj(interp,objv[2],&centerx)) return TCL_ERROR;
  16115. if(Tcl_GetDoubleFromObj(interp,objv[3],&centery)) return TCL_ERROR;
  16116. pResult=Tcl_NewObj();
  16117. for(i=4;i<objc;i+=2) {
  16118. double x,y,newx,newy;
  16119. if(Tcl_GetDoubleFromObj(interp,objv[i],&x)) {
  16120. Tcl_DecrRefCount(pResult);
  16121. return TCL_ERROR;
  16122. }
  16123. if(Tcl_GetDoubleFromObj(interp,objv[i+1],&y)) {
  16124. Tcl_DecrRefCount(pResult);
  16125. return TCL_ERROR;
  16126. }
  16127. newx=(x/zoom)+centerx;
  16128. newy=(y/zoom)+centery;
  16129. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newx));
  16130. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(newy));
  16131. }
  16132. Tcl_SetObjResult(interp, pResult);
  16133. return TCL_OK;
  16134. }
  16135. /* Tcl Proc ::vector2d::point_on_segment */
  16136. static int TclCmd_vector2d_point_on_segment(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16137. double x1,y1,x2,y2,x3,y3;
  16138. if( objc != 7 ){
  16139. Tcl_WrongNumArgs(interp, 1, objv, "point_on_segment x y x1 y1 x2 y2");
  16140. return TCL_ERROR;
  16141. }
  16142. if (Tcl_GetDoubleFromObj(interp,objv[1],&x1)) return TCL_ERROR;
  16143. if (Tcl_GetDoubleFromObj(interp,objv[2],&y1)) return TCL_ERROR;
  16144. if (Tcl_GetDoubleFromObj(interp,objv[3],&x2)) return TCL_ERROR;
  16145. if (Tcl_GetDoubleFromObj(interp,objv[4],&y2)) return TCL_ERROR;
  16146. if (Tcl_GetDoubleFromObj(interp,objv[5],&x3)) return TCL_ERROR;
  16147. if (Tcl_GetDoubleFromObj(interp,objv[6],&y3)) return TCL_ERROR;
  16148. Tcl_SetObjResult(interp, Tcl_NewIntObj(Vector2d_PointIsOnSegment(x1,y1,x2,y2,x3,y3)));
  16149. return TCL_OK;
  16150. }
  16151. /* Tcl Proc ::vector2d::line_circle_intersect */
  16152. static int TclCmd_vector2d_line_circle_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16153. double ax1,ax2,ay1,ay2;
  16154. double bx1,by1,brad;
  16155. double ix,iy;
  16156.  
  16157. if(objc<8) {
  16158. Tcl_WrongNumArgs(interp, 1, objv, "ax1 ay1 ax2 ay2 bx1 by1 brad");
  16159. return TCL_ERROR;
  16160. }
  16161.  
  16162. if( Tcl_GetDoubleFromObj(interp, objv[1], &ax1) ) return TCL_ERROR;
  16163. if( Tcl_GetDoubleFromObj(interp, objv[2], &ay1) ) return TCL_ERROR;
  16164. if( Tcl_GetDoubleFromObj(interp, objv[3], &ax2) ) return TCL_ERROR;
  16165. if( Tcl_GetDoubleFromObj(interp, objv[4], &ay2) ) return TCL_ERROR;
  16166.  
  16167. if( Tcl_GetDoubleFromObj(interp, objv[5], &bx1) ) return TCL_ERROR;
  16168. if( Tcl_GetDoubleFromObj(interp, objv[6], &by1) ) return TCL_ERROR;
  16169. if( Tcl_GetDoubleFromObj(interp, objv[7], &brad) ) return TCL_ERROR;
  16170.  
  16171. if(ODIE_Math_LineCircleIntersect(ax1,ay1,ax2,ay2,bx1,by1,brad,&ix,&iy)) {
  16172. Tcl_Obj *pResult;
  16173. pResult = Tcl_NewObj();
  16174. Tcl_ListObjAppendElement(interp, pResult, Tcl_NewDoubleObj(ix));
  16175. Tcl_ListObjAppendElement(interp, pResult, Tcl_NewDoubleObj(iy));
  16176. Tcl_SetObjResult(interp, pResult);
  16177. }
  16178. return TCL_OK;
  16179. }
  16180. /* Tcl Proc ::vector2d::line_intersect */
  16181. static int TclCmd_vector2d_line_intersect(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16182. double ax1,ax2,ay1,ay2;
  16183. double bx1,bx2,by1,by2;
  16184. double ix,iy;
  16185.  
  16186. if(objc<9) {
  16187. Tcl_WrongNumArgs(interp, 1, objv, "ax1 ay1 ax2 ay2 bx1 by1 bx2 by2");
  16188. return TCL_ERROR;
  16189. }
  16190.  
  16191. if( Tcl_GetDoubleFromObj(interp, objv[1], &ax1) ) return TCL_ERROR;
  16192. if( Tcl_GetDoubleFromObj(interp, objv[2], &ay1) ) return TCL_ERROR;
  16193. if( Tcl_GetDoubleFromObj(interp, objv[3], &ax2) ) return TCL_ERROR;
  16194. if( Tcl_GetDoubleFromObj(interp, objv[4], &ay2) ) return TCL_ERROR;
  16195.  
  16196. if( Tcl_GetDoubleFromObj(interp, objv[5], &bx1) ) return TCL_ERROR;
  16197. if( Tcl_GetDoubleFromObj(interp, objv[6], &by1) ) return TCL_ERROR;
  16198. if( Tcl_GetDoubleFromObj(interp, objv[7], &bx2) ) return TCL_ERROR;
  16199. if( Tcl_GetDoubleFromObj(interp, objv[8], &by2) ) return TCL_ERROR;
  16200.  
  16201. if(ODIE_Math_LineLineIntersect(ax1,ay1,ax2,ay2,bx1,by1,bx2,by2,&ix,&iy)) {
  16202. Tcl_Obj *pResult;
  16203. pResult = Tcl_NewObj();
  16204. Tcl_ListObjAppendElement(interp, pResult, Tcl_NewDoubleObj(ix));
  16205. Tcl_ListObjAppendElement(interp, pResult, Tcl_NewDoubleObj(iy));
  16206. Tcl_SetObjResult(interp, pResult);
  16207. }
  16208. return TCL_OK;
  16209. }
  16210. /* Tcl Proc ::vector2d::line_overlap */
  16211. static int TclCmd_vector2d_line_overlap(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16212. Tcl_Obj *pResult;
  16213. double ax1,ax2,ay1,ay2;
  16214. double bx1,bx2,by1,by2;
  16215.  
  16216. if(objc<9) {
  16217. Tcl_WrongNumArgs(interp, 1, objv, "ax1 ay1 ax2 ay2 bx1 by1 bx2 by2");
  16218. return TCL_ERROR;
  16219. }
  16220.  
  16221. if( Tcl_GetDoubleFromObj(interp, objv[1], &ax1) ) return TCL_ERROR;
  16222. if( Tcl_GetDoubleFromObj(interp, objv[2], &ay1) ) return TCL_ERROR;
  16223. if( Tcl_GetDoubleFromObj(interp, objv[3], &ax2) ) return TCL_ERROR;
  16224. if( Tcl_GetDoubleFromObj(interp, objv[4], &ay2) ) return TCL_ERROR;
  16225.  
  16226. if( Tcl_GetDoubleFromObj(interp, objv[5], &bx1) ) return TCL_ERROR;
  16227. if( Tcl_GetDoubleFromObj(interp, objv[6], &by1) ) return TCL_ERROR;
  16228. if( Tcl_GetDoubleFromObj(interp, objv[7], &bx2) ) return TCL_ERROR;
  16229. if( Tcl_GetDoubleFromObj(interp, objv[8], &by2) ) return TCL_ERROR;
  16230.  
  16231. /*
  16232. ** ignore if the segments connect at endpoints
  16233. if(ax1==bx1 && ay1==by1) return TCL_OK;
  16234. if(ax1==bx2 && ay1==by2) return TCL_OK;
  16235. if(ax2==bx1 && ay2==by1) return TCL_OK;
  16236. if(ax2==bx2 && ay2==by2) return TCL_OK;
  16237. */
  16238.  
  16239. pResult = Tcl_NewIntObj(Vector2d_LineLineCoincident(ax1,ay1,ax2,ay2,bx1,by1,bx2,by2));
  16240. Tcl_SetObjResult(interp, pResult);
  16241.  
  16242. return TCL_OK;
  16243. }
  16244. /* Tcl Proc ::vector2d::colinear */
  16245. static int TclCmd_vector2d_colinear(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16246. double x1,y1,x2,y2,x3,y3;
  16247. if( objc != 7 ){
  16248. Tcl_WrongNumArgs(interp, 1, objv, "colinear x1 y1 x2 y2 x3 y3");
  16249. return TCL_ERROR;
  16250. }
  16251. if (Tcl_GetDoubleFromObj(interp,objv[1],&x1)) return TCL_ERROR;
  16252. if (Tcl_GetDoubleFromObj(interp,objv[2],&y1)) return TCL_ERROR;
  16253. if (Tcl_GetDoubleFromObj(interp,objv[3],&x2)) return TCL_ERROR;
  16254. if (Tcl_GetDoubleFromObj(interp,objv[4],&y2)) return TCL_ERROR;
  16255. if (Tcl_GetDoubleFromObj(interp,objv[5],&x3)) return TCL_ERROR;
  16256. if (Tcl_GetDoubleFromObj(interp,objv[6],&y3)) return TCL_ERROR;
  16257. Tcl_SetObjResult(interp, Tcl_NewBooleanObj(Vector2d_IsColinear(x1,y1,x2,y2,x3,y3)));
  16258. return TCL_OK;
  16259. }
  16260. /* Tcl Proc ::vector3d::compare */
  16261. static int TclCmd_vector3d_compare(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16262. VectorXY A, B;
  16263. int c;
  16264. if( objc!=7 ){
  16265. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 Z0 X1 Y1 Z1");
  16266. return TCL_ERROR;
  16267. }
  16268. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  16269. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  16270. if( Odie_GetMatrixElementFromObj(interp, objv[3], A, Z_IDX) ) return TCL_ERROR;
  16271. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, X_IDX) ) return TCL_ERROR;
  16272. if( Odie_GetMatrixElementFromObj(interp, objv[5], B, Y_IDX) ) return TCL_ERROR;
  16273. if( Odie_GetMatrixElementFromObj(interp, objv[6], B, Z_IDX) ) return TCL_ERROR;
  16274. c=VectorXYZ_SamePoint(A,B);
  16275. Tcl_SetObjResult(interp, Tcl_NewBooleanObj(c));
  16276. return TCL_OK;
  16277. }
  16278. /* Tcl Proc ::vector3d::add */
  16279. static int TclCmd_vector3d_add(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16280. VectorXYZ A, B, P;
  16281. Tcl_Obj *pResult;
  16282. if( objc!=7 ){
  16283. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 Z0 X1 Y1 Z1");
  16284. return TCL_ERROR;
  16285. }
  16286. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  16287. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  16288. if( Odie_GetMatrixElementFromObj(interp, objv[3], A, Z_IDX) ) return TCL_ERROR;
  16289. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, X_IDX) ) return TCL_ERROR;
  16290. if( Odie_GetMatrixElementFromObj(interp, objv[5], B, Y_IDX) ) return TCL_ERROR;
  16291. if( Odie_GetMatrixElementFromObj(interp, objv[6], B, Z_IDX) ) return TCL_ERROR;
  16292. VectorXYZ_Add(P,A,B);
  16293. pResult=Tcl_NewObj();
  16294. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[X_IDX]));
  16295. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[Y_IDX]));
  16296. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[Z_IDX]));
  16297. Tcl_SetObjResult(interp, pResult);
  16298. return TCL_OK;
  16299. }
  16300. /* Tcl Proc ::vector3d::subtract */
  16301. static int TclCmd_vector3d_subtract(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16302. VectorXYZ A, B, P;
  16303. Tcl_Obj *pResult;
  16304. if( objc!=7 ){
  16305. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 Z0 X1 Y1 Z1");
  16306. return TCL_ERROR;
  16307. }
  16308. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  16309. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  16310. if( Odie_GetMatrixElementFromObj(interp, objv[3], A, Z_IDX) ) return TCL_ERROR;
  16311. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, X_IDX) ) return TCL_ERROR;
  16312. if( Odie_GetMatrixElementFromObj(interp, objv[5], B, Y_IDX) ) return TCL_ERROR;
  16313. if( Odie_GetMatrixElementFromObj(interp, objv[6], B, Z_IDX) ) return TCL_ERROR;
  16314. VectorXYZ_Subtract(P,A,B);
  16315. pResult=Tcl_NewObj();
  16316. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[X_IDX]));
  16317. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[Y_IDX]));
  16318. Tcl_ListObjAppendElement(interp,pResult,Tcl_NewDoubleObj(P[Z_IDX]));
  16319. Tcl_SetObjResult(interp, pResult);
  16320. return TCL_OK;
  16321. }
  16322. /* Tcl Proc ::vector3d::orthagonal */
  16323. static int TclCmd_vector3d_orthagonal(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16324. int result;
  16325. VectorXY A, B;
  16326. if( objc!=7 ){
  16327. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 Z0 X1 Y1 Z1");
  16328. return TCL_ERROR;
  16329. }
  16330. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  16331. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  16332. if( Odie_GetMatrixElementFromObj(interp, objv[3], A, Z_IDX) ) return TCL_ERROR;
  16333. if( Odie_GetMatrixElementFromObj(interp, objv[4], B, X_IDX) ) return TCL_ERROR;
  16334. if( Odie_GetMatrixElementFromObj(interp, objv[5], B, Y_IDX) ) return TCL_ERROR;
  16335. if( Odie_GetMatrixElementFromObj(interp, objv[6], B, Z_IDX) ) return TCL_ERROR;
  16336. Tcl_SetObjResult(interp,Tcl_NewBooleanObj(VectorXYZ_IsOrthagonal(A,B)));
  16337. return TCL_OK;
  16338. }
  16339. /* Tcl Proc ::vector3d::distance */
  16340. static int TclCmd_vector3d_distance(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
  16341. double result;
  16342. VectorXY A, B;
  16343. if( objc!=7 ){
  16344. Tcl_WrongNumArgs(interp, 1, objv, "X0 Y0 Z0 X1 Y1 Z1");
  16345. return TCL_ERROR;
  16346. }
  16347. if( Odie_GetMatrixElementFromObj(interp, objv[1], A, X_IDX) ) return TCL_ERROR;
  16348. if( Odie_GetMatrixElementFromObj(interp, objv[2], A, Y_IDX) ) return TCL_ERROR;
  16349. if( Odie_GetMatrixElementFromObj(interp, objv[3], A, Z_IDX) ) retu