home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 13 / 13.iso / p / p024 / 16.img / AME3.LIB / TUTOR.C < prev    next >
Encoding:
Text File  |  1992-06-17  |  77.1 KB  |  2,626 lines

  1. /* Next available MSG number is 115 */
  2.  
  3. /************************************************************************
  4. Name: tutor.c
  5.  
  6. Description: AME/API sample program for API tutorial. 
  7.  
  8. Author: AME Group
  9.         Autodesk, Inc.
  10.  
  11.  
  12.  
  13.  
  14. Copyright (C) 1992 by Autodesk, Inc.
  15. **************************************************************************
  16. *                                                                        *
  17. *    Permission to use, copy, modify, and distribute this software       *
  18. *    for any purpose and without fee is hereby granted, provided         *
  19. *    that the above copyright notice appears in all copies and that      *
  20. *    both that copyright notice and this permission notice appear in     *
  21. *    all supporting documentation.                                       *
  22. *                                                                        *
  23. *    THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED        *
  24. *    WARRANTY.  ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR     *
  25. *    PURPOSE AND OF MERCHANTABILITY ARE HEREBY DISCLAIMED.               *
  26. *                                                                        *
  27. *                                                                        *
  28. *    The objective of this tutorial program is to illustrate the         *
  29. *    fundamental concepts, data structure and 3D solid modelling power   *
  30. *    of AME/API application programming interface. The program uses a    *
  31. *    wide variety of API functions to build practical utility and        *
  32. *    applications.  It is designed specifically for beginners aiming     * 
  33. *    at ease of understanding, self-learning and full coverage of the    *
  34. *    the API scope. The tutorial program encompasses the following key   *
  35. *    API features:                                                       *
  36. *                                                                        *
  37. *                                                                        *
  38. *         Object creation and manipulation                               *
  39. *         Interrogation of topological relationships                     *
  40. *         Object information data structure                              *
  41. *         Face information data structure                                *
  42. *         Edge information data structure                                *
  43. *         Entity membership classification                               *
  44. *         Mass properties application                                    *
  45. *                                                                        *
  46. *                                                                        *
  47. *    Seven new commands are available in this program to illustrate      * 
  48. *    the principle and technique associated with the above seven key     *
  49. *    API features respectively.  The commands set and the corresponding  *
  50. *    function calls are shown as follows:                                *
  51. *                                                                        *
  52. *         SOLPIPE  - create_pipe()                                       *
  53. *         SOLTOPOL - query_topology_relations()                          *
  54. *         SOLTRACE - trace_object_history()                              *
  55. *         SOLNORM  - query_face_normal                                   *
  56. *         SOLTAN   - query_edge_tangent()                                *
  57. *         SOLCLASS - classify_entity_membership()                        *
  58. *         SOLUCSPD - set_ucs_to_prindir()                                *
  59. *                                                                        *
  60. *                                                                        *
  61. *    The command "SOLPIPE" illustrates a typical example for object      *
  62. *    creation, manipulation and display. It allows the user to create    *
  63. *    a geometric model of pipe by specifying inner and outer diameters,  *
  64. *    start and end points of the pipe. In API, the geometry of a simple  *
  65. *    object can be created in several different ways.  These include     *
  66. *    primitive (cylinder, cone, sphere, torus, wedge), extruding and     *
  67. *    revolving a 2D polyline or region.  After solid models of simple    * 
  68. *    objects are created, they can be combined into complex solid        *
  69. *    (called composite solid) by Boolean operations such as union,       *
  70. *    intersection and subtraction.  They can be edited by scaling        *
  71. *    cutting, separation and deletion. Objects can be moved and rotated  *
  72. *    as rigid motion by matrix transformation.  API provides various     * 
  73. *    methods for user to obtain the desired 4X4 transformation matrix    *
  74. *    by translation, rotating about X, Y, Z and arbitrary axis           *
  75. *    respectively, axial alignment, 3-points locating and access to      *
  76. *    current ucs matrix etc.  In API environment, all new objects are    * 
  77. *    created in world coordinate system and are always invisible until   *
  78. *    you actually post them on the screen.                               *
  79. *                                                                        *
  80. *         Command:  solpipe                                              *
  81. *         Enter inner diameter <0.8>:                                    *
  82. *         Enter outer diameter <1.0>:                                    * 
  83. *         Start point <0,0,0>:                                           *
  84. *         End point <0,0,1>:                                             *
  85. *                                                                        *
  86. *                                                                        *
  87. *    The command "SOLTOPOL" illustrates an example for querying          *
  88. *    topological relationship.  It counts the total number of faces,     *
  89. *    edges and vertices associated with a selected object.               *
  90. *    Solid models are established on the basis of complete geometric     *
  91. *    information and sound topological relationship.  The topological    *
  92. *    elements of an object consist of bodys, faces, edges and vertices.  *
  93. *    The object's topology deals with the structure and adjacency of     * 
  94. *    the topological elements such as finding all edges surrounding a    *
  95. *    given vertex, finding the two faces sharing the given edge,         *
  96. *    finding all edges associated with a given face etc. ap_Facelist     *
  97. *    and ap_Edgelist are the data structures that can support these      *
  98. *    applications.                                                       *
  99. *                                                                        *
  100. *         Command:  SOLTOPOL                                             *
  101. *         Select an object:                                              *
  102. *                                                                        *
  103. *                                                                        *
  104. *    The command "SOLTRACE illustrates how to traverse CSG tree and      *
  105. *    retrieve object information data structure from a given object.     *
  106. *    The object information data structure ap_Objinfo contains           * 
  107. *    object_type, sizes, material, color, transformation matrix,         *
  108. *    parent, left child and right child.  The object type may include    *
  109. *    box, cylinder,cone, sphere, torus, wedge, composite, extrusion,     *
  110. *    revolution, fillet and chamfer.  Each object type is defined by     *
  111. *    the associated parameters such as length, width and height with     *
  112. *    respect to world coordinate system at its own initial position.     *
  113. *    THe transformation matrix reflects the current location and         *
  114. *    orientation of the object in the world coordinate system. Parent,   *
  115. *    left child and right child are created to form CSG binary tree      *
  116. *    structure for boolean operations.                                   *
  117. *                                                                        *
  118. *         Command:  SOLTRACE                                             *
  119. *         Select an object:                                              *
  120. *                                                                        *
  121. *                                                                        *
  122. *    The command "SOLNORM" illustrates how to retrieve and use face      *
  123. *    information data structure to verify whether a specified point      *
  124. *    is on a selected face or not.  It calculates the unit normal to     *
  125. *    the selected face at specified point or its projection on the face. * 
  126. *    Face information data structure ap_Faceinfo contains surface_type,  *
  127. *    surface_parameters, transformation matrix, and perimeter.           * 
  128. *    Currently, API supports five types of surfaces: planar, cylinder,   *
  129. *    conical, spherical, and toroidal. Each type of surface is defined   * 
  130. *    by the associated parameters such as x_radius and y_radius at       * 
  131. *    initial position with respect to wcs. The transformation matrix     * 
  132. *    represents the current location and orientation of the surface      *
  133. *    in the global world coordinate system.                              *
  134. *                                                                        *
  135. *         Command:  SOLNORM                                              *
  136. *         Select a face:                                                 * 
  137. *         Point on the face:                                             * 
  138. *                                                                        *
  139. *                                                                        *
  140. *     The command "SOLTAN" illustrates how to retrieve and use edge      *
  141. *     information to project a specified point onto a selected edge.     *
  142. *     It calculates the unit tangent of the selected edge at the         *
  143. *     specified point or its projection on the edge. The edge            * 
  144. *     information data structure ap_Edgeinfo contains curve_type,        *
  145. *     parameters, transformation matrix, endpoints and length.           *
  146. *     In this release, API supports six types of curve: line, ellipse,   *
  147. *     parabola, hyperbola, cylcyl and concon.  Each type of curve is     * 
  148. *     defined by the associated parameters such as x_radius and y_radius *
  149. *     at initial position with respect to world coordinate system. The   *
  150. *     transformation matrix stores the current location and orientation  *
  151. *     of the curve in the world coordinate system.                       * 
  152. *                                                                        *
  153. *         Command:  SOLTAN                                               *
  154. *         Select an edge:                                                *
  155. *         Point on the edge:                                             *
  156. *                                                                        *
  157. *                                                                        *
  158. *     The command "SOLCLASS" illustrates how to use API functions        *
  159. *     to classify a point or a line against a selected object.           *
  160. *     Entity membership classification is the fundamentals of any solid  *
  161. *     modeling system.  It classifies point, lines or curves with        *
  162. *     respect to a solid as either on, in or out of the object.          * 
  163. *     In the case of partially in and partially out, it breaks the       *
  164. *     curve into segments and classifies them as either on, in           *
  165. *     or out of a given object.  The data structures relating to the     *
  166. *     membership classification are ap_Seglist, ap_Edgeseg and           *
  167. *     ap_Class.                                                          *
  168. *                                                                        *
  169. *         Command:  SOLCLASS                                             *
  170. *         Line/<Point>: P                                                *
  171. *         Point <0,0,0>:                                                 *
  172. *         Select an object:                                              *
  173. *                                                                        *
  174. *         Command:  SOLCLASS                                             *
  175. *         Line/<Point>: L                                                *
  176. *         From <0,0,0>:                                                  *
  177. *         To <0,0,1>:                                                    *
  178. *         Select an object:                                              *
  179. *                                                                        *
  180. *    The command "SOLUCSPD" uses mass property data structure to obtain  *
  181. *    centroid and principal moment directions from a given object.       *
  182. *    It then uses these information to reset the current ucs to locate   *
  183. *    at the centroid and align it to the principal moment directions     *
  184. *    of the selected object. The mass properties data structure          *
  185. *    ap_Massprop contains information such as mass, volume, area         *
  186. *    centroid, moment of inertia, product of inertia, radii of gyration  *
  187. *    and principal mement directions.                                    *
  188. *                                                                        *
  189. *         Command:  SOLUCSPD                                             *
  190. *         Select an object:                                              *
  191. *                                                                        *
  192. *                                                                        *
  193. *    To use these new commands, you have to compile the program and      *
  194. *    xload the executable code (after loading AME) into AutoCAD system.  *
  195. *                                                                        *
  196. **************************************************************************
  197.  
  198.  
  199. Modification history:
  200.     Refer to the RCS section at the end of this file.
  201.  
  202. Bugs and restrictions on use:
  203.  
  204. Notes:
  205.  
  206. **************************************************************************/
  207.  
  208.  
  209. /*************************************************************************/
  210. /* Includes */
  211. /*************************************************************************/
  212.  
  213. #include <stdio.h>
  214. #include <math.h>
  215. #include <adslib.h>
  216. #include <aplib.h>
  217.  
  218. /*************************************************************************/
  219. /* Defines */
  220. /*************************************************************************/
  221.  
  222. #define  PI   3.141596
  223. #define  EPSILON  1.0e-6
  224. #define  POINT       0
  225. #define  LINE        1
  226. #define  RED         1
  227. #define  YELLOW      2
  228. #define  BLUE        3
  229. #define  PMAX       16
  230. #define  OFF         0
  231. #define  ON          1
  232. #define  ORIGIN      2
  233.  
  234. #define  MALLOC(x)  ((x *) malloc ((unsigned long)sizeof (x)))
  235. #define  CALLOC(n, x)  ((x *) calloc (n, (unsigned long)sizeof(x)))
  236. #define  REALLOC(p, n, x) ((x *) realloc (p, n*(unsigned long) \
  237. sizeof(x)))
  238.  
  239. #ifndef ELEMENTS
  240. #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
  241. #endif
  242.  
  243. struct resbuf  Echo1, Echo2;
  244.  
  245. /*************************************************************************/
  246. /* Typedefs */
  247. /*************************************************************************/
  248.  
  249. typedef  struct  vertex_table {
  250.     unsigned long   nv;
  251.     unsigned long   size;
  252.     ads_point   *fv;
  253. } v_table;
  254.  
  255. /*************************************************************************/
  256. /* Global variables */
  257. /*************************************************************************/
  258.  
  259. struct resbuf  Echo1, Echo2;
  260. int   table_size = 50;
  261. int   step = 10;
  262. int   gap = 2;
  263. int   screen_pagelen = 24;
  264. int   screen_lineno = 0;
  265.  
  266. /*************************************************************************/
  267. /* Function type declaration */
  268. /*************************************************************************/
  269.  
  270. /* main & ads support functions */
  271.  
  272. void     main();
  273. int      funcload();
  274. void     print_new_command_set();
  275. void     command_echo_off();
  276. void     command_echo_on();
  277.  
  278. /* Functions for solpipe command */
  279.  
  280. void     create_pipe ();
  281. ap_Bool  get_pipe_data();
  282.  
  283. /* Functions for soltopol command */
  284.  
  285. void     query_topology_relations();
  286. ap_Bool  count_vertices_of_obj();
  287. v_table  *init_vtable();
  288. ap_Bool  insert_pt_to_vtable();
  289. void     free_vtable();
  290.  
  291. /* Functions for soltrace command */
  292.  
  293. void     trace_object_history();
  294. ap_Bool  select_object();
  295. ap_Bool  traverse_and_dump_tree();
  296. ap_Bool  linechk();
  297. void     print_obj_info();
  298. void     print_trans_matrix();
  299. void     print_pline_vertex();
  300.  
  301. /* Functions for solnorm command */
  302.  
  303. void     query_face_normal();
  304. ap_Bool  verify_pt_on_surface();
  305. ap_Bool  verify_pt_on_plane();
  306. ap_Bool  verify_pt_on_cyl();
  307. ap_Bool  verify_pt_on_cone();
  308. ap_Bool  verify_pt_on_sph();
  309. ap_Bool  verify_pt_on_tor();
  310.  
  311. /* Functions for soltan command */
  312.  
  313. void     query_edge_tangent();
  314. ap_Bool  proj_pt_on_curve();
  315. ap_Bool  evalu_pt_on_curve();
  316.  
  317. /* Functions for solclass command */
  318.  
  319. void     classify_entity_membership();
  320. void     print_pt_class();
  321. ap_Bool  get_line_data();
  322. ap_Bool  make_edgeinfo_from_line();
  323. void     print_line_class();
  324.  
  325. /* Functions for solucspd command */
  326.  
  327. void     set_ucs_to_prindir();
  328. ap_Bool  get_region_pts();
  329. ap_Bool  set_current_ucs();
  330. void     turn_ucsicon();
  331.  
  332. /* Functions for graphics support */
  333.  
  334. ap_Bool  draw_virtual_arrow();
  335. ap_Bool  draw_virtual_arrowhead();
  336. ap_Bool  draw_virtual_line();
  337. ap_Bool  draw_virtual_circle();
  338.  
  339. /* Mathematic utilitity functions */
  340.  
  341. ap_Bool  get_xdir_from_zdir();
  342. void     copy_point();
  343. void     set_point();
  344. ap_Bool  verify_2pts_equal();
  345. void     combine_vector();
  346. ap_Bool  normalize_vector();
  347. void     cross_vector();
  348. void     trans_pt_by_matrix();
  349. void     trans_uc2wc();
  350. void     trans_wc2uc();
  351. ads_real find_minimum();
  352.  
  353.  
  354. /*************************************************************************/
  355. /* Commands definition and dispatch table */
  356. /*************************************************************************/
  357.  
  358. struct ads_comm {
  359.     char   *cmdname;
  360.     void   (*cmdfunc) ();
  361. };
  362.  
  363. struct ads_comm cmdtab[] = {
  364.      {/*MSG1*/"C:SOLPIPE", create_pipe},
  365.      {/*MSG2*/"C:SOLTOPOL", query_topology_relations},
  366.      {/*MSG3*/"C:SOLTRACE", trace_object_history},
  367.      {/*MSG4*/"C:SOLNORM", query_face_normal},
  368.      {/*MSG5*/"C:SOLTAN", query_edge_tangent},
  369.      {/*MSG6*/"C:SOLCLASS",classify_entity_membership},
  370.      {/*MSG7*/"C:SOLUCSPD",set_ucs_to_prindir},
  371.     };
  372.  
  373.  
  374. /*************************************************************************/
  375. /* .doc main() */
  376. /*+
  377. -*/
  378. /*************************************************************************/
  379.  
  380. void
  381. /*FCN*/main(argc, argv)
  382.   int             argc;
  383.   char           *argv[];
  384. {
  385.     int             stat, cindex;
  386.     short           scode = 1;
  387.  
  388.     ads_init(argc, argv);
  389.  
  390.     while (TRUE) {
  391.         if ((stat = ads_link(scode)) < 0) {
  392.             printf(/*MSG8*/"TUTOR: bad status from ads_link() = %d\n",
  393.                    stat);
  394.             fflush(stdout);
  395.             ads_exit(1);
  396.         }
  397.         scode = -RSRSLT;
  398.  
  399.         switch (stat) {
  400.         case RQXLOAD:                 /* Load & register functions */
  401.             scode = -(funcload() ? RSRSLT : RSERR);
  402.             scode = -RSRSLT;
  403.             print_new_command_set();
  404.             break;
  405.  
  406.         case RQSUBR:                  /* Evaluate external lisp function */
  407.             cindex = ads_getfuncode();
  408.             (*cmdtab[cindex].cmdfunc) ();
  409.             break;
  410.  
  411.         case RQXUNLD:                 /* Unloading */
  412.             ads_printf (/*MSG9*/"Unloading: ");
  413.             break;
  414.  
  415.         case RQSAVE:                  /* AutoCAD SAVE notification */
  416.             break;
  417.  
  418.         case RQQUIT:                  /* AutoCAD QUIT notification */
  419.             break;
  420.  
  421.         case RQEND:                   /* AutoCAD END notification */
  422.             break;
  423.  
  424.         default:
  425.             break;
  426.  
  427.         }
  428.     }
  429. }
  430.  
  431. /*************************************************************************/
  432. /* .doc funcload() */
  433. /*+
  434.    Load external functions into AutoCAD system
  435. -*/
  436. /*************************************************************************/
  437.  
  438. static int 
  439. /*FCN*/funcload()
  440.  
  441. {
  442.     int             i;
  443.  
  444.     for (i = 0; i < ELEMENTS(cmdtab); i++) {
  445.         if(! ads_defun (cmdtab[i].cmdname , i))
  446.             return  RTERROR;
  447.     }
  448.     return RTNORM;
  449. }
  450.  
  451. /*************************************************************************/
  452. /* .doc print_new_command_set() */
  453. /*+
  454.    Print new commands on the screen when the program is loaded 
  455. -*/
  456. /*************************************************************************/
  457.  
  458. static  void
  459. /*FCN*/print_new_command_set()
  460. {
  461.     ads_printf(/*MSG10*/"\nNew loaded commands:");
  462.     ads_printf(/*MSG11*/"\nSOLPIPE, SOLTOPOL, SOLTRACE, SOLNORM, ");
  463.     ads_printf(/*MSG12*/"SOLTAN, SOLCLASS, SOLUCSPD\n");
  464. }
  465.  
  466. /*************************************************************************/
  467. /* .doc command_echo_off() */
  468. /*+
  469.    Suppress command echo
  470. -*/
  471. /*************************************************************************/
  472.  
  473. static void
  474. /*FCN*/command_echo_off()
  475. {
  476.     ads_getvar (/*MSG0*/"CMDECHO", &Echo1);
  477.     Echo2.restype = RTSHORT;
  478.     Echo2.resval.rint = FALSE;
  479.     ads_setvar (/*MSG0*/"CMDECHO", &Echo2);
  480. }
  481.  
  482. /*************************************************************************/
  483. /* .doc command_echo_on() */
  484. /*+
  485.    Resume command echo
  486. -*/
  487. /*************************************************************************/
  488.  
  489. static void
  490. /*FCN*/command_echo_on()
  491. {
  492.     ads_setvar (/*MSG0*/"CMDECHO", &Echo1);
  493. }
  494.  
  495.  
  496. /*************************************************************************/
  497. /* .doc create_pipe() */
  498. /*+
  499.    This routine executes SOLPIPE command and creates a pipe
  500. -*/
  501. /*************************************************************************/
  502.  
  503. static void
  504. /*FCN*/create_pipe()
  505.  
  506. {
  507.     ap_Real  pipe_d1 = 0.8;
  508.     ap_Real  pipe_d2 = 1.0;
  509.     ap_Real  rad1, rad2, pipe_l;
  510.     static ads_point  pts[3], pt1, pt2;
  511.     ap_Trans3d  matrix;
  512.     ap_Objid  Cyl1, Cyl2, Pipe;
  513.     int stat;
  514.  
  515.     /* Initialize API */
  516.  
  517.     stat = ap_init();
  518.     if (stat != AP_NORMAL)
  519.         goto Error;
  520.  
  521.     /* Prompt pipe data from the user */
  522.  
  523.     stat = get_pipe_data(&pipe_d1, &pipe_d2, pt1, pt2);
  524.     if (stat == FALSE)
  525.         goto Error;
  526.  
  527.     /* Convert pipe diameter to radius and calculate pipe length */
  528.  
  529.     rad1 = pipe_d1 / 2.0;
  530.     rad2 = pipe_d2 / 2.0;
  531.     pipe_l = ads_distance(pt1, pt2);
  532.  
  533.     /* Create inner cylinder */
  534.  
  535.     stat = ap_cylinder (rad1, rad1, pipe_l, &Cyl1);
  536.     if (stat != AP_NORMAL) {
  537.         ads_printf(/*MSG13*/"\nUnable to create cylinder.");
  538.         goto Error;
  539.     }
  540.  
  541.     /* Create outer cylinder */
  542.  
  543.     stat = ap_cylinder (rad2, rad2, pipe_l, &Cyl2);
  544.     if (stat != AP_NORMAL) {
  545.         ads_printf(/*MSG14*/"\nUnable to create cylinder.");
  546.         goto Error;
  547.     }
  548.  
  549.     /* Subtract inner from outer cylinder to produce a pipe */
  550.  
  551.     stat = ap_subtract (Cyl2, Cyl1, &Pipe);
  552.     if (stat != AP_NORMAL) {
  553.         ads_printf(/*MSG15*/"\nUnable to create pipe.\n");
  554.         goto Error;
  555.     }
  556.  
  557.     /* Transform points pt1 & pt2 from UCS into WCS */
  558.  
  559.     trans_uc2wc(pt1, FALSE, pts[0]);
  560.     trans_uc2wc(pt2, FALSE, pts[1]);
  561.  
  562.     /* Setup transformation matrix to align pipe's center line
  563.            from Z-axis to new direction specified by pt1 & pt2 */
  564.  
  565.     ap_pts2xfm(pts, 2, matrix);
  566.  
  567.     /* Move pipe to new location by the matrix */
  568.  
  569.     ap_move_obj (Pipe, matrix, TRUE);
  570.  
  571.     /* Display the pipe on the screen */
  572.  
  573.     ap_post_obj (Pipe, AP_POSTWIRE);
  574.  
  575. Error:
  576.     ads_retvoid();
  577.     return;
  578. }
  579.  
  580. /*************************************************************************/
  581. /* .doc get_pipe_data() */
  582. /*+
  583.    This routine prompts the user to enter pipe's data of
  584.    inner and outer diameters, start and end points. 
  585. -*/
  586. /*************************************************************************/
  587. static ap_Bool
  588. /*FCN*/get_pipe_data(dia1, dia2, pc1, pc2)
  589.   ads_real   *dia1, *dia2;
  590.   ads_point  pc1, pc2;
  591. {
  592.     int stat;
  593.  
  594.     /* Initialization of data for default */
  595.  
  596.     *dia1 = 0.8;
  597.     *dia2 = 1.0;
  598.     set_point(0.0, 0.0, 0.0, pc1);
  599.     set_point(0.0, 0.0, 1.0, pc2);
  600.  
  601.     stat = ads_getreal (/*MSG16*/"\nEnter inner diameter <0.8>: ", dia1);
  602.     if (stat == RTCAN)
  603.         return FALSE;
  604.  
  605.     /* Verify positive pipe inner diameter */
  606.  
  607.     if (*dia1 <= 0.0) {
  608.         ads_printf(/*MSG17*/"\nInvalid pipe diameter.");
  609.         return FALSE;
  610.     }
  611.  
  612.     stat = ads_getreal (/*MSG18*/"\nEnter outer diameter <1.0>: ", dia2);
  613.     if (stat == RTCAN)
  614.         return FALSE;
  615.  
  616.     /* Verify positive pipe outer diameter */
  617.  
  618.     if ((*dia2 <= 0.0) || (*dia2 <= *dia1)) {
  619.         ads_printf(/*MSG19*/"\nInvalid pipe diameter.");
  620.         return FALSE;
  621.     }
  622.  
  623.     /* Prompt the user to select the start point for the pipe */
  624.  
  625.     stat = ads_getpoint (NULL, /*MSG20*/"\nStart point <0,0,0>: ", pc1);
  626.     if ((stat == RTCAN) || (stat == RTERROR))
  627.         return FALSE;
  628.  
  629.     /* Prompt the user to select the end point for the pipe */
  630.  
  631.     stat = ads_getpoint (pc1, /*MSG21*/"\nEnd point <0,0,1>: ", pc2);
  632.     if ((stat == RTCAN) || (stat == RTERROR))
  633.         return FALSE;
  634.  
  635.     /* Verify that the selected two points are not coincident */
  636.  
  637.     stat = verify_2pts_equal(pc1, pc2);
  638.     if(stat == TRUE) {
  639.         ads_printf (/*MSG22*/"\nInvalid pipe length.\n");
  640.         return FALSE;
  641.     }
  642.  
  643.     return TRUE;
  644. }
  645.  
  646. /*************************************************************************/
  647. /* .doc query_topology_relations() */
  648. /*+
  649.    This routine counts and outputs the total number of faces,
  650.    edges and verticies of a given solid
  651. -*/
  652. /*************************************************************************/
  653.  
  654. static void
  655. /*FCN*/query_topology_relations()
  656. {
  657.     ap_Objid Object;
  658.     ap_Edgelist  *elist, *el;
  659.     ap_Facelist  *flist, *sl;
  660.     ads_name chosen;
  661.     int  stat;
  662.     long  nface, nedge, nvertex;
  663.     ads_point  loc;
  664.  
  665.     /* Initialize API */
  666.  
  667.     stat = ap_init();
  668.     if (stat != AP_NORMAL)
  669.         goto Error0;
  670.  
  671.     stat = select_object(&Object, chosen, loc);
  672.     if(stat == FALSE)
  673.         goto Error0;
  674.  
  675.     /* Highlight the selected solid */
  676.  
  677.     ads_redraw(chosen, 3);
  678.  
  679.     stat = ap_obj2faces(Object, FALSE, &flist);
  680.     if (stat != AP_NORMAL) {
  681.         ads_printf (/*MSG23*/"\nUnable to retrieve face list.");
  682.         goto Error1;
  683.     }
  684.  
  685.     /* count the faces */
  686.  
  687.     nface = 0;
  688.     for(sl=flist; sl != NULL; sl=sl->facenext)
  689.         nface++;
  690.     ap_free_facelist(flist);
  691.  
  692.     stat = ap_obj2edges(Object, FALSE, &elist);
  693.     if (stat != AP_NORMAL) {
  694.         ads_printf (/*MSG24*/"\nUnable to retrieve edge list.");
  695.         goto Error1;
  696.     }
  697.  
  698.     /* count the edges */
  699.  
  700.     nedge = 0;
  701.     for(el=elist; el != NULL; el=el->edgenext)
  702.         nedge++;
  703.     ap_free_edgelist(elist);
  704.  
  705.     /* count the vertices */
  706.  
  707.     stat = count_vertices_of_obj(Object, &nvertex);
  708.  
  709.     ads_printf (/*MSG25*/"\nNumber of faces = %d", nface);
  710.     ads_printf (/*MSG26*/"\nNumber of edges = %d", nedge);
  711.     ads_printf (/*MSG27*/"\nNumber of vertices = %d", nvertex);
  712.  
  713.     /* Dehighlight the selected solid */
  714.  
  715. Error1:
  716.     ads_redraw(chosen, 4);
  717.  
  718. Error0:
  719.     ads_retvoid();
  720.     return;
  721. }
  722.  
  723. /*************************************************************************/
  724. /* .doc count_vertices_of_obj() */
  725. /*+
  726.    This routine counts the total number of verticies 
  727.    of a given solid
  728. -*/
  729. /*************************************************************************/
  730. static ap_Bool
  731. /*FCN*/count_vertices_of_obj(sol, nv)
  732.   ap_Objid  sol;
  733.   long   *nv;
  734. {
  735.     v_table *vtb;
  736.     ap_Edgelist  *elist, *el;
  737.     ads_point  p1, p2;
  738.     int  stat;
  739.  
  740.     stat = ap_obj2edges(sol, TRUE, &elist);
  741.     if (stat != AP_NORMAL) {
  742.         ads_printf (/*MSG28*/"\nUnable to retrieve edge list.");
  743.         return FALSE;
  744.     }
  745.  
  746.     vtb = init_vtable();
  747.     if (vtb == NULL) {
  748.         ads_printf (/*MSG29*/"\nUnable to open vertex table.");
  749.         return FALSE;
  750.     }
  751.  
  752.     for(el=elist; el != NULL; el=el->edgenext) {
  753.         copy_point(el->edge->s_pt, p1);
  754.         copy_point(el->edge->e_pt, p2);
  755.         insert_pt_to_vtable(p1, vtb);
  756.         insert_pt_to_vtable(p2, vtb);
  757.     }
  758.  
  759.     *nv = vtb->nv;
  760.     ap_free_edgelist(elist);
  761.     free_vtable(vtb);
  762.     return TRUE;
  763. }
  764.  
  765. /*************************************************************************/
  766. /* .doc init_vtable() */
  767. /*+
  768.    This routine initializes a table for storing vertices (points)
  769. -*/
  770. /*************************************************************************/
  771. static v_table *
  772. /*FCN*/init_vtable ()
  773. {
  774.     v_table  *p;
  775.     ads_point  *q;
  776.  
  777.     if ((p = MALLOC (v_table)) == NULL)
  778.     {
  779.         ads_printf(/*MSG30*/"\n\nCan't allocate memory for vertex table.");
  780.         ads_retvoid();
  781.         return NULL;
  782.     }
  783.     else
  784.     {
  785.         if ((q = CALLOC (table_size, ads_point)) == NULL)
  786.         {
  787.             ads_printf(/*MSG31*/"\n\nCan't allocate memory for vertex table!\n");
  788.             free (p);
  789.             return NULL;
  790.         }
  791.  
  792.         p->nv = 0;
  793.         p->size = table_size;
  794.         p->fv = q;
  795.         return p ;
  796.     }
  797. }
  798.  
  799. /*************************************************************************/
  800. /* .doc insert_pt_to_vtable() */
  801. /*+
  802.    This routine inserts a 3D point into vertex table
  803.    The point will be rejected if it already exists 
  804.    in the table
  805. -*/
  806. /*************************************************************************/
  807. static  ap_Bool
  808. /*FCN*/insert_pt_to_vtable (pt, vb)
  809.   ads_point  pt;
  810.   v_table  *vb;
  811. {
  812.     ads_point   *q;
  813.     int   i, index, tablesize;
  814.     ads_point  pq;
  815.     ap_Bool  stat;
  816.  
  817.     index = vb->nv;
  818.     tablesize = vb->size;
  819.     q = vb->fv;
  820.  
  821.     if (index >= 1)
  822.     {
  823.         for (i=0; i<index; i++)
  824.         {
  825.             pq[X] = q[i][X];
  826.             pq[Y] = q[i][Y];
  827.             pq[Z] = q[i][Z];
  828.  
  829.             stat = verify_2pts_equal (pt, pq);
  830.             if (stat == TRUE)
  831.                 return FALSE;
  832.         }
  833.     }
  834.  
  835.     if (index == (tablesize - gap))
  836.     {
  837.         tablesize = tablesize + step;
  838.  
  839.         if ((q = REALLOC(q, tablesize, ads_point)) == NULL)
  840.         {
  841.             ads_printf
  842.             (/*MSG32*/"\n\nCan't allocate memory for vertex\n");
  843.             return FALSE;
  844.  
  845.         }
  846.     }
  847.  
  848.     q[index][X] = pt[X];
  849.     q[index][Y] = pt[Y];
  850.     q[index][Z] = pt[Z];
  851.  
  852.     vb->nv = index + 1;
  853.     vb->size = tablesize;
  854.     vb->fv = q;
  855.     return TRUE;
  856. }
  857.  
  858. /*************************************************************************/
  859. /* .doc free_vtable() */
  860. /*+
  861.    This routine cleans the vertex table to free the membery
  862. -*/
  863. /*************************************************************************/
  864. static void 
  865. /*FCN*/free_vtable (p)
  866.   v_table  *p;
  867. {
  868.     ads_point  *q;
  869.  
  870.     if ( p == NULL)
  871.         return;
  872.  
  873.     q = p->fv;
  874.     if(q != NULL)
  875.         free (q);
  876.     free(p);
  877. }
  878.  
  879. /*************************************************************************/
  880. /* .doc trace_object_history() */
  881. /*+
  882.    This routine executes command SOLTRACE 
  883. -*/
  884. /*************************************************************************/
  885.  
  886. static void
  887. /*FCN*/trace_object_history ()
  888. {
  889.     ap_Objid Object;
  890.     ads_name chosen;
  891.     ads_point  loc;
  892.     int      stat;
  893.  
  894.     /* Initialize API */
  895.  
  896.     stat = ap_init();
  897.     if (stat != AP_NORMAL)
  898.         goto Error;
  899.  
  900.     stat = select_object(&Object, chosen, loc);
  901.     if(stat == FALSE)
  902.         goto Error;
  903.  
  904.     /* Highlight the selected object */
  905.  
  906.     ads_redraw(chosen, 3);
  907.  
  908.     ads_textpage();
  909.     screen_lineno = 0;
  910.     linechk(3);
  911.     ads_printf
  912.     (/*MSG33*/"\n\n--- CSG HISTORY FOR OBJECT ID = %d ---\n", Object);
  913.     traverse_and_dump_tree(Object);
  914.  
  915.     /* Dehighlight the object */
  916.  
  917.     ads_redraw(chosen, 4);
  918.  
  919. Error:
  920.     ads_retvoid();
  921.     return;
  922. }
  923.  
  924. /*************************************************************************/
  925. /* .doc select_object() */
  926. /*+
  927.    This routine prompts the user to select an object
  928. -*/
  929. /*************************************************************************/
  930.  
  931. static ap_Bool
  932. /*FCN*/select_object (sol, ename, loc)
  933.   ap_Objid  *sol;
  934.   ads_name   ename;
  935.   ads_point  loc;
  936. {
  937.     int  stat;
  938.  
  939.     stat = ads_entsel(/*MSG34*/"Select an object:", ename, loc);
  940.     if(stat != RTNORM) {
  941.         ads_retvoid();
  942.         return FALSE;
  943.     }
  944.  
  945.     /* Verify that the selected entity is an AME object */
  946.  
  947.     stat = ap_name2obj(ename, sol);
  948.     if(stat == AP_NORMAL) {
  949.         ads_retvoid();
  950.         return TRUE;
  951.     } else {
  952.         ads_retvoid();
  953.         return FALSE;
  954.     }
  955. }
  956.  
  957. /*************************************************************************/
  958. /* .doc traverse_and_dump_tree() */
  959. /*+
  960.    This routine traverses the CSG tree recursively in
  961.    postorder: left child, right child, and root
  962. -*/
  963. /*************************************************************************/
  964. static ap_Bool
  965. /*FCN*/traverse_and_dump_tree(obj)
  966.   ap_Objid   obj;
  967. {
  968.     int stat;
  969.     ap_Objinfo  oinfo;
  970.  
  971.     /* Retrieve object information */
  972.  
  973.     stat = ap_get_objinfo(obj, &oinfo);
  974.     if(stat != AP_NORMAL) {
  975.         ads_printf(/*MSG35*/"\nCan't retrieve solid information.");
  976.         return FALSE;
  977.     }
  978.  
  979.     if(oinfo.type == AP_BOO) {
  980.  
  981.         /* Left child */
  982.  
  983.         traverse_and_dump_tree(oinfo.prim.boo.op1);
  984.  
  985.         /* Right child */
  986.  
  987.         traverse_and_dump_tree(oinfo.prim.boo.op2);
  988.     }
  989.  
  990.     /* Dump object information */
  991.  
  992.     print_obj_info(obj, oinfo);
  993.     return TRUE;
  994. }
  995.  
  996. /*************************************************************************/
  997. /* .doc print_obj_info() */
  998. /*+
  999.    This routine outputs object information
  1000. -*/
  1001. /*************************************************************************/
  1002.  
  1003. static void
  1004. /*FCN*/print_obj_info(sid, sol)
  1005.   ap_Objid   sid;
  1006.   ap_Objinfo  sol;
  1007. {
  1008.     ads_real   dx, dy, dz, da;
  1009.     ap_Objid  c1, c2;
  1010.     long  np;
  1011.  
  1012.     linechk(2);
  1013.     switch(sol.type) {
  1014.     case AP_BOX:
  1015.         dx = sol.prim.box.x;
  1016.         dy = sol.prim.box.y;
  1017.         dz = sol.prim.box.z;
  1018.         ads_printf(/*MSG36*/"\nCreate: %lu = BOX (%f, %f, %f)\n", sid,dx,dy,dz);
  1019.         print_trans_matrix(sol.mat);
  1020.         break;
  1021.  
  1022.     case AP_CON:
  1023.         dx = sol.prim.con.rx;
  1024.         dy = sol.prim.con.ry;
  1025.         dz = sol.prim.con.h;
  1026.         ads_printf(/*MSG37*/"\nCreate: %lu = CONE (%f, %f, %f)\n", sid,dx,dy,dz);
  1027.         print_trans_matrix(sol.mat);
  1028.         break;
  1029.  
  1030.     case AP_CYL:
  1031.         dx = sol.prim.cyl.rx;
  1032.         dy = sol.prim.cyl.ry;
  1033.         dz = sol.prim.cyl.h;
  1034.         ads_printf(/*MSG38*/"\nCreate: %lu = CYLINDER (%f, %f, %f)\n", sid,dx,dy,dz);
  1035.         print_trans_matrix(sol.mat);
  1036.         break;
  1037.  
  1038.     case AP_SPH:
  1039.         dx = sol.prim.sph.r;
  1040.         ads_printf(/*MSG39*/"\nCreate: %lu = SPHERE (%f)\n", sid, dx);
  1041.         print_trans_matrix(sol.mat);
  1042.         break;
  1043.  
  1044.     case AP_TOR:
  1045.         dx = sol.prim.tor.rmaj;
  1046.         dy = sol.prim.tor.rmin;
  1047.         ads_printf(/*MSG40*/"\nCreate: %lu = TORUS (%f, %f)\n", sid, dx, dy);
  1048.         print_trans_matrix(sol.mat);
  1049.         break;
  1050.  
  1051.     case AP_WED:
  1052.         dx = sol.prim.wed.x;
  1053.         dy = sol.prim.wed.y;
  1054.         dz = sol.prim.wed.z;
  1055.         ads_printf(/*MSG41*/"\nCreate: %lu = WEDGE (%f, %f, %f)\n", sid,dx,dy,dz);
  1056.         print_trans_matrix(sol.mat);
  1057.         break;
  1058.  
  1059.     case AP_BOO:
  1060.         c1 = sol.prim.boo.op1;
  1061.         c2 = sol.prim.boo.op2;
  1062.         if(sol.prim.boo.op == AP_SUBTRACT)
  1063.             ads_printf(/*MSG42*/"\nBoolean: %lu =  %lu subtract by %lu\n", sid,c1,c2);
  1064.         else if(sol.prim.boo.op == AP_INT)
  1065.             ads_printf(/*MSG43*/"\nBoolean: %lu =  %lu intersect %lu\n", sid,c1,c2);
  1066.         else if(sol.prim.boo.op == AP_UNION)
  1067.             ads_printf(/*MSG44*/"\nBoolean: %lu =  %lu join %lu\n", sid,c1,c2);
  1068.         else
  1069.             ads_printf(/*MSG45*/"\nUnknown Solid\n");
  1070.  
  1071.         print_trans_matrix(sol.mat);
  1072.         break;
  1073.  
  1074.     case AP_EXT:
  1075.         np = sol.prim.ext.n;
  1076.         dz = sol.prim.ext.h;
  1077.         da = sol.prim.ext.taper;
  1078.         ads_printf(/*MSG46*/"\nCreate: %lu = EXTRUSION (%lu, %f, %f)\n",sid,np,dz,da);
  1079.         if(dz < 0)
  1080.             print_pline_vertex(np, sol.prim.ext.pts, TRUE);
  1081.         else
  1082.             print_pline_vertex(np, sol.prim.ext.pts, FALSE);
  1083.  
  1084.         print_trans_matrix(sol.mat);
  1085.         break;
  1086.  
  1087.     case AP_REV:
  1088.         np = sol.prim.rev.n;
  1089.         da = sol.prim.rev.angle;
  1090.         ads_printf(/*MSG47*/"\nCreate: %lu = REVOLUTION (%d, %f)\n", sid,np,da);
  1091.         print_pline_vertex(np, sol.prim.rev.pts, FALSE);
  1092.         print_trans_matrix(sol.mat);
  1093.         break;
  1094.  
  1095.     case AP_FIL:
  1096.         dx = sol.prim.fil.r;
  1097.         ads_printf(/*MSG48*/"\nCreate: %lu = FILLET (%f) ", sid, dx);
  1098.         if(sol.prim.fil.type == AP_STRAIGHT)
  1099.             ads_printf(/*MSG49*/"Straignt_Edge\n");
  1100.         else if(sol.prim.fil.type == AP_CIRCULAR)
  1101.             ads_printf(/*MSG50*/"Circular_Edge\n");
  1102.         else
  1103.             ads_printf(/*MSG51*/"Undefined_Edge\n");
  1104.  
  1105.         print_trans_matrix(sol.mat);
  1106.         break;
  1107.  
  1108.     case AP_CHA:
  1109.         dx = sol.prim.cha.d1;
  1110.         dy = sol.prim.cha.d2;
  1111.         ads_printf(/*MSG52*/"\nCreate: %lu = CHAMFER (%f %f) ", sid,dx,dy);
  1112.         if(sol.prim.fil.type == AP_STRAIGHT)
  1113.             ads_printf(/*MSG53*/"Straignt_Edge\n");
  1114.         else if(sol.prim.fil.type == AP_CIRCULAR)
  1115.             ads_printf(/*MSG54*/"Circular_Edge\n");
  1116.         else
  1117.             ads_printf(/*MSG55*/"Undefined_Edge\n");
  1118.  
  1119.         print_trans_matrix(sol.mat);
  1120.         break;
  1121.  
  1122.     case AP_CIR:
  1123.         dx = sol.prim.cir.r;
  1124.         ads_printf(/*MSG56*/"\nCreate: %lu = CIRCLE (%f)\n", sid,dx);
  1125.         print_trans_matrix(sol.mat);
  1126.         break;
  1127.  
  1128.     case AP_POLY:
  1129.         np = sol.prim.poly.n;
  1130.         ads_printf(/*MSG57*/"\nCreate: %lu = POLYLINE (%d)\n", sid, np);
  1131.         print_pline_vertex(np, sol.prim.poly.pts, FALSE);
  1132.         print_trans_matrix(sol.mat);
  1133.         break;
  1134.  
  1135.     default:
  1136.         ads_printf(/*MSG58*/"\nUnknown SOLID\n");
  1137.         break;
  1138.     }
  1139. }
  1140.  
  1141. /*************************************************************************/
  1142. /* .doc print_trans_matrix() */
  1143. /*+
  1144.    This routine outputs the transformation matrix
  1145. -*/
  1146. /*************************************************************************/
  1147. static void
  1148. /*FCN*/print_trans_matrix(m)
  1149.   ap_Trans3d  m;
  1150. {
  1151.     int i;
  1152.  
  1153.     linechk(5);
  1154.     ads_printf(/*MSG59*/"Transformation Matrix:\n");
  1155.     for(i=0; i<4; i++)
  1156.         ads_printf("     %+f %+f %+f %+f\n",
  1157.                    m[i][0], m[i][1], m[i][2], m[i][3]);
  1158. }
  1159.  
  1160. /*************************************************************************/
  1161. /* .doc print_pline_vertex() */
  1162. /*+
  1163.    This routine outputs the coordinates of vertices in polyline
  1164. -*/
  1165. /*************************************************************************/
  1166. static void
  1167. /*FCN*/print_pline_vertex(np, pts, xmirror)
  1168.   long  np;
  1169.   ap_Swp_pts  *pts;
  1170.   ap_Bool  xmirror;
  1171. {
  1172.     long i;
  1173.     ap_Real  xt;
  1174.  
  1175.     linechk((int)(np+1));
  1176.     ads_printf(/*MSG60*/"Polyline vertices and type:\n");
  1177.     for(i=0; i<np; i++) {
  1178.         xt = xmirror ? -pts[i].x : pts[i].x;
  1179.         if(pts[i].type == AP_PT_ARCEND)
  1180.             ads_printf(/*MSG61*/"    (%+f %+f) Arc_Edge\n", xt, pts[i].y);
  1181.         else if(pts[i].type == AP_PT_LINE)
  1182.             ads_printf(/*MSG62*/"    (%+f %+f) Line_Edge\n", xt, pts[i].y);
  1183.         else
  1184.             ;
  1185.     }
  1186. }
  1187.  
  1188. /*************************************************************************/
  1189. /*.doc linechk() */
  1190. /*+
  1191.     This routine determines if we've printed a whole screen's worth of
  1192.     data, and if so, will put the prompt "Hit Enter for more ..."
  1193. -*/
  1194. /*************************************************************************/
  1195.  
  1196. static ap_Bool
  1197. /*FCN*/linechk(n)
  1198.   int n;
  1199. {
  1200.     char    buf[128];
  1201.  
  1202.     if (screen_pagelen == 0)
  1203.         return TRUE;
  1204.  
  1205.     screen_lineno = screen_lineno + n;
  1206.  
  1207.     if (screen_lineno >= screen_pagelen) {
  1208.         if (ads_getstring(0, /*MSG63*/"Hit Enter for more ...", buf) < 0) {
  1209.             screen_lineno = (screen_lineno - screen_pagelen) + 1;
  1210.             return FALSE;
  1211.         }
  1212.         screen_lineno = (screen_lineno - screen_pagelen) + 1;
  1213.         ads_printf("\r                               \r");
  1214.     }
  1215.     return TRUE;
  1216. }
  1217.  
  1218. /*************************************************************************/
  1219. /* .doc query_face_normal() */
  1220. /*+
  1221.    This routine executes command SOLNORM and calculates
  1222.    the unit normal to a given face at the specified point
  1223. -*/
  1224. /*************************************************************************/
  1225.  
  1226. static void
  1227. /*FCN*/query_face_normal()
  1228. {
  1229.     ap_Objid Object;
  1230.     ap_Featid  face;
  1231.     ads_point  pc, pd, pe, pt, ps;
  1232.     int      stat, stat_pt;
  1233.  
  1234.     /* Initialize API */
  1235.  
  1236.     stat = ap_init();
  1237.     if (stat != AP_NORMAL)
  1238.         goto Error;
  1239.  
  1240.     stat = ap_sel_face ("", &Object, &face);
  1241.     if (stat != AP_NORMAL)
  1242.     {
  1243.         ads_printf(/*MSG64*/"\nUnable to get the face");
  1244.         goto Error;
  1245.     }
  1246.  
  1247.     stat = ads_getpoint(NULL, /*MSG65*/"\nPoint on the face:", pt);
  1248.     if ((stat == RTCAN) || (stat == RTERROR))
  1249.         goto Error;
  1250.  
  1251.     trans_uc2wc(pt, FALSE, pc);
  1252.  
  1253.     stat_pt = verify_pt_on_surface(Object, face, pc);
  1254.     if(stat_pt == TRUE) {
  1255.         stat = ap_pt_norm2face(Object, face, pc, TRUE, pd);
  1256.         if (stat != AP_NORMAL)
  1257.         {
  1258.             ads_printf(/*MSG66*/"\nUnable to obtain face normal.");
  1259.             goto Error;
  1260.         }
  1261.         copy_point(pc, ps);
  1262.     } else {
  1263.         stat = ap_pt2face(Object, face, pc, ps);
  1264.         if ((stat != AP_NORMAL) && (stat != AP_SINGULARITY))
  1265.         {
  1266.             ads_printf(/*MSG67*/"\nUnable to obtain projection point.");
  1267.             goto Error;
  1268.         }
  1269.  
  1270.         stat = ap_pt_norm2face(Object, face, ps, TRUE, pd);
  1271.         if (stat != AP_NORMAL)
  1272.         {
  1273.             ads_printf(/*MSG68*/"\nUnable to obtain face normal.");
  1274.             goto Error;
  1275.         }
  1276.     }
  1277.  
  1278.     /* Draw the unit normal vector on the screen */
  1279.  
  1280.     combine_vector(1.0, ps, 1.0, pd, pe);
  1281.     draw_virtual_arrow(ps, pe, YELLOW, FALSE);
  1282.  
  1283.     /* Convert points from wcs to ucs for printput */
  1284.  
  1285.     trans_wc2uc(pc, FALSE, pc);
  1286.     trans_wc2uc(pd, TRUE, pd);
  1287.  
  1288.     if(stat_pt == TRUE) {
  1289.         ads_printf(/*MSG69*/"\nSelected point = (%+f, %+f, %+f)", pc[X],pc[Y],pc[Z]);
  1290.         ads_printf(/*MSG70*/"\nUnit normal    = (%+f, %+f, %+f)", pd[X],pd[Y],pd[Z]);
  1291.     } else {
  1292.         trans_wc2uc(ps, FALSE, ps);
  1293.         ads_printf(/*MSG71*/"\nSelected point = (%+f, %+f, %+f)", pc[X],pc[Y],pc[Z]);
  1294.         ads_printf(/*MSG72*/"\nProjection pt  = (%+f, %+f, %+f)", ps[X],ps[Y],ps[Z]);
  1295.         ads_printf(/*MSG73*/"\nUnit normal    = (%+f, %+f, %+f)", pd[X],pd[Y],pd[Z]);
  1296.     }
  1297.  
  1298. Error:
  1299.     ads_retvoid();
  1300.     return;
  1301.  
  1302. }
  1303.  
  1304. /*************************************************************************/
  1305. /* .doc verify_pt_on_surface() */
  1306. /*+
  1307.    This routine verifies a point with a given surface
  1308.    It returns TRUE if the point lies on the surface
  1309. -*/
  1310. /*************************************************************************/
  1311.  
  1312. static ap_Bool
  1313. /*FCN*/verify_pt_on_surface(sol, fe, pt)
  1314.   ap_Objid  sol;
  1315.   ap_Featid  fe;
  1316.   ads_point  pt;
  1317. {
  1318.     ap_Faceinfo  *finfo;
  1319.     int   stat, status;
  1320.  
  1321.     stat = ap_get_faceinfo(sol, fe, &finfo);
  1322.     if (stat != AP_NORMAL) {
  1323.         ads_printf (/*MSG74*/"\nUnable to retrieve face information");
  1324.         return FALSE;
  1325.     }
  1326.  
  1327.     switch(finfo->stype) {
  1328.     case AP_PLANAR:
  1329.         status = verify_pt_on_plane(finfo, pt);
  1330.         break;
  1331.  
  1332.     case AP_CYLINDRICAL:
  1333.         status = verify_pt_on_cyl(finfo, pt);
  1334.         break;
  1335.  
  1336.     case AP_CONICAL:
  1337.         status = verify_pt_on_cone(finfo, pt);
  1338.         break;
  1339.  
  1340.     case AP_SPHERICAL:
  1341.         status = verify_pt_on_sph(finfo, pt);
  1342.         break;
  1343.  
  1344.     case AP_TOROIDAL:
  1345.         status = verify_pt_on_tor(finfo, pt);
  1346.         break;
  1347.  
  1348.     default:
  1349.         status = FALSE;
  1350.         break;
  1351.     }
  1352.  
  1353.     ap_free_faceinfo(finfo);
  1354.     return status;
  1355. }
  1356.  
  1357. /*************************************************************************/
  1358. /* .doc verify_pt_on_plane() */
  1359. /*+
  1360.    This routine returns TRUE if the point lies on the given plane
  1361. -*/
  1362. /*************************************************************************/
  1363.  
  1364. static ap_Bool
  1365. /*FCN*/verify_pt_on_plane(finfo, pt)
  1366.   ap_Faceinfo *finfo;
  1367.   ads_point  pt;
  1368. {
  1369.     ads_point pq;
  1370.     ap_Trans3d minv;
  1371.  
  1372.     if(finfo->stype != AP_PLANAR)
  1373.         return FALSE;
  1374.  
  1375.     ap_invert(finfo->face_rm, minv);
  1376.     trans_pt_by_matrix(minv, pt, pq);
  1377.  
  1378.     if(fabs(pq[Z]) < EPSILON)
  1379.         return TRUE;
  1380.     else
  1381.         return FALSE;
  1382. }
  1383.  
  1384. /*************************************************************************/
  1385. /* .doc verify_pt_on_cyl() */
  1386. /*+
  1387.    This routine returns TRUE if the point lies on the given cylinder 
  1388. -*/
  1389. /*************************************************************************/
  1390.  
  1391. static ap_Bool
  1392. /*FCN*/verify_pt_on_cyl(finfo, pt)
  1393.   ap_Faceinfo *finfo;
  1394.   ads_point  pt;
  1395. {
  1396.     ap_Trans3d minv;
  1397.     ads_point pq;
  1398.     ads_real  radx, rady, tx, ty, dr;
  1399.  
  1400.     if(finfo->stype != AP_CYLINDRICAL)
  1401.         return FALSE;
  1402.  
  1403.     radx = finfo->surf.cyl.rx;
  1404.     rady = finfo->surf.cyl.ry;
  1405.  
  1406.     ap_invert(finfo->face_rm, minv);
  1407.     trans_pt_by_matrix(minv, pt, pq);
  1408.     tx = pq[X]/radx;
  1409.     ty = pq[Y]/rady;
  1410.     dr = tx * tx + ty * ty - 1.0;
  1411.  
  1412.     if(fabs(dr) < EPSILON)
  1413.         return TRUE;
  1414.     else
  1415.         return FALSE;
  1416. }
  1417.  
  1418. /*************************************************************************/
  1419. /* .doc verify_pt_on_cone() */
  1420. /*+
  1421.    This routine returns TRUE if the point lies on the given cone 
  1422. -*/
  1423. /*************************************************************************/
  1424.  
  1425. static ap_Bool
  1426. /*FCN*/verify_pt_on_cone(finfo, pt)
  1427.   ap_Faceinfo *finfo;
  1428.   ads_point  pt;
  1429. {
  1430.     ap_Trans3d minv;
  1431.     ads_point pq;
  1432.     ads_real  radx, rady, tx, ty, dr;
  1433.  
  1434.     if(finfo->stype != AP_CONICAL)
  1435.         return FALSE;
  1436.  
  1437.     radx = finfo->surf.con.rx;
  1438.     rady = finfo->surf.con.ry;
  1439.  
  1440.     ap_invert(finfo->face_rm, minv);
  1441.     trans_pt_by_matrix(minv, pt, pq);
  1442.     tx = pq[X]/radx;
  1443.     ty = pq[Y]/rady;
  1444.     dr = tx * tx + ty * ty - pq[Z] * pq[Z];
  1445.  
  1446.     if(fabs(dr) < EPSILON)
  1447.         return TRUE;
  1448.     else
  1449.         return FALSE;
  1450. }
  1451.  
  1452. /*************************************************************************/
  1453. /* .doc verify_pt_on_sph() */
  1454. /*+
  1455.    This routine returns TRUE if the point lies on the given sphere 
  1456. -*/
  1457. /*************************************************************************/
  1458.  
  1459. static ap_Bool
  1460. /*FCN*/verify_pt_on_sph(finfo, pt)
  1461.   ap_Faceinfo *finfo;
  1462.   ads_point  pt;
  1463. {
  1464.     ap_Trans3d minv;
  1465.     ads_point pq;
  1466.     ads_real  rad, dr;
  1467.  
  1468.     if(finfo->stype != AP_SPHERICAL)
  1469.         return FALSE;
  1470.  
  1471.     rad = finfo->surf.sph.r;
  1472.     ap_invert(finfo->face_rm, minv);
  1473.     trans_pt_by_matrix(minv, pt, pq);
  1474.     dr = pq[X]*pq[X] + pq[Y]*pq[Y]+ pq[Z]*pq[Z] - rad*rad;
  1475.  
  1476.     if(fabs(dr) < EPSILON)
  1477.         return TRUE;
  1478.     else
  1479.         return FALSE;
  1480. }
  1481.  
  1482. /*************************************************************************/
  1483. /* .doc verify_pt_on_tor() */
  1484. /*+
  1485.    This routine returns TRUE if the point lies on the given torus 
  1486. -*/
  1487. /*************************************************************************/
  1488.  
  1489. static ap_Bool
  1490. /*FCN*/verify_pt_on_tor(finfo, pt)
  1491.   ap_Faceinfo *finfo;
  1492.   ads_point  pt;
  1493. {
  1494.     ap_Trans3d minv;
  1495.     ads_point pq;
  1496.     ads_real  rad1, rad2, dt, dr, result;
  1497.  
  1498.     if(finfo->stype != AP_TOROIDAL)
  1499.         return FALSE;
  1500.  
  1501.     rad1 = finfo->surf.tor.rmaj;
  1502.     rad2 = finfo->surf.tor.rmin;
  1503.  
  1504.     ap_invert(finfo->face_rm, minv);
  1505.     trans_pt_by_matrix(minv, pt, pq);
  1506.     dt = pq[X]*pq[X] + pq[Y]*pq[Y]+ pq[Z]*pq[Z];
  1507.     dr = dt - rad1*rad1 - rad2*rad2;
  1508.     result = dr * dr - 4*rad1*rad1*(rad2*rad2-pq[Z]*pq[Z]);
  1509.     if(fabs(result) < EPSILON)
  1510.         return TRUE;
  1511.     else
  1512.         return FALSE;
  1513. }
  1514.  
  1515. /*************************************************************************/
  1516. /* .doc query_edge_tangent() */
  1517. /*+
  1518.    This routine executes command SOLTAN.
  1519.    It calculates and displays unit tangent of a given 
  1520.    curve at the selected location.
  1521. -*/
  1522. /*************************************************************************/
  1523.  
  1524. static void
  1525. /*FCN*/query_edge_tangent()
  1526. {
  1527.     ap_Objid Object;
  1528.     ap_Featid  edge;
  1529.     ads_point  pc, pd, pe, pq, pt;
  1530.     ads_real   parm;
  1531.     int      stat;
  1532.  
  1533.     /* Initialize API */
  1534.  
  1535.     stat = ap_init();
  1536.     if (stat != AP_NORMAL)
  1537.         goto Error;
  1538.  
  1539.     stat = ap_sel_edge ("", &Object, &edge);
  1540.     if (stat != AP_NORMAL)
  1541.     {
  1542.         ads_printf(/*MSG75*/"\nUnable to get the edge");
  1543.         goto Error;
  1544.     }
  1545.  
  1546.     stat = ads_getpoint(NULL, /*MSG76*/"\nPoint on the edge:", pt);
  1547.     if ((stat == RTCAN) || (stat == RTERROR))
  1548.         goto Error;
  1549.  
  1550.     trans_uc2wc(pt, FALSE, pq);
  1551.  
  1552.     stat = ap_pt_tang2edge(Object, edge, pq, pd);
  1553.     if (stat != AP_NORMAL) {
  1554.         proj_pt_on_curve(Object, edge, pq, pc, &parm);
  1555.         stat = ap_pt_tang2edge(Object, edge, pc, pd);
  1556.         if (stat != AP_NORMAL) {
  1557.             ads_printf(/*MSG77*/"\nUnable to obtain edge tangent.");
  1558.             goto Error;
  1559.         }
  1560.     } else
  1561.         copy_point(pq, pc);
  1562.  
  1563.     /* Draw the unit tangent vector on the screen */
  1564.  
  1565.     combine_vector(1.0, pc, 1.0, pd, pe);
  1566.     draw_virtual_arrow(pc, pe, YELLOW, FALSE);
  1567.  
  1568.     /* Convert points from wcs to ucs for printout */
  1569.  
  1570.     trans_wc2uc(pc, FALSE, pc);
  1571.     trans_wc2uc(pq, FALSE, pq);
  1572.     trans_wc2uc(pd, TRUE, pd);
  1573.     stat = verify_2pts_equal(pc, pq);
  1574.     if(stat == TRUE) {
  1575.         ads_printf(/*MSG78*/"\nSelected point = (%+f, %+f, %+f)",pq[X],pq[Y],pq[Z]);
  1576.         ads_printf(/*MSG79*/"\nUnit tangent   = (%+f, %+f, %+f)",pd[X],pd[Y],pd[Z]);
  1577.     } else {
  1578.         ads_printf(/*MSG80*/"\nSelected point = (%+f, %+f, %+f)",pq[X],pq[Y],pq[Z]);
  1579.         ads_printf(/*MSG81*/"\nProjection pt  = (%+f, %+f, %+f)",pc[X],pc[Y],pc[Z]);
  1580.         ads_printf(/*MSG82*/"\nUnit tangent   = (%+f, %+f, %+f)",pd[X],pd[Y],pd[Z]);
  1581.     }
  1582.  
  1583. Error:
  1584.     ads_retvoid();
  1585.     return;
  1586. }
  1587.  
  1588. /*************************************************************************/
  1589. /* .doc proj_pt_on_curve() */
  1590. /*+
  1591.    This routine projects a point onto a given curve.
  1592.    It returns a pt on the curve which is nearest to the input.
  1593. -*/
  1594. /*************************************************************************/
  1595.  
  1596. static ap_Bool
  1597. /*FCN*/proj_pt_on_curve(sol, edge, pin, pout, parm)
  1598.   ap_Objid  sol;
  1599.   ap_Featid  edge;
  1600.   ads_point  pin, pout;
  1601.   ads_real   *parm;
  1602. {
  1603.     ap_Edgeinfo  *einfo;
  1604.     ap_Trans3d minv;
  1605.     ads_point pc, pt;
  1606.     ads_real  t, t1, t2, dt;
  1607.     ads_real  len, dismin, da[101];
  1608.     ap_Bool  repeat = TRUE;
  1609.     int  stat, i, index, status, np = 101;
  1610.  
  1611.  
  1612.     stat = ap_get_edgeinfo(sol, edge, &einfo);
  1613.     if (stat != AP_NORMAL)
  1614.     {
  1615.         ads_printf(/*MSG83*/"\nUnable to obtain edge information.");
  1616.         return FALSE;
  1617.     }
  1618.  
  1619.     t1 = einfo->s_parm;
  1620.     t2 = einfo->e_parm;
  1621.     len = fabs(t2 - t1);
  1622.     ap_invert(einfo->edge_rm, minv);
  1623.     trans_pt_by_matrix(minv, pin, pc);
  1624.  
  1625.     while (repeat == TRUE) {
  1626.         dt = (t2 - t1) / (np - 1);
  1627.         for(i=0; i<np; i++) {
  1628.             t = t1 + i * dt;
  1629.             stat = evalu_pt_on_curve(einfo, t, pt);
  1630.             if(stat == FALSE) {
  1631.                 status = FALSE;
  1632.                 break;
  1633.             }
  1634.  
  1635.             da[i] = ads_distance(pt, pc);
  1636.         }
  1637.         dismin = find_minimum(da, np, &index);
  1638.         t = t1 + index * dt;
  1639.  
  1640.         if(fabs(dt) < (EPSILON * len)) {
  1641.             evalu_pt_on_curve(einfo, t, pt);
  1642.             trans_pt_by_matrix(einfo->edge_rm, pt, pout);
  1643.             *parm = t;
  1644.             status = TRUE;
  1645.             repeat = FALSE;
  1646.         } else if(index == 0) {
  1647.             t1 = t;
  1648.             t2 = t + dt;
  1649.         } else if(index == (np-1)) {
  1650.             t1 = t - dt;
  1651.             t2 = t;
  1652.         } else {
  1653.             t1 = t - dt/2;
  1654.             t2 = t + dt/2;
  1655.         }
  1656.     }
  1657.  
  1658.     ap_free_edgeinfo(einfo);
  1659.     return status;
  1660. }
  1661.  
  1662. /*************************************************************************/
  1663. /* .doc evalu_pt_on_curve() */
  1664. /*+
  1665.    This routine calculates the coordinate of a point 
  1666.    on the parametric curve at the specified value.
  1667. -*/
  1668. /*************************************************************************/
  1669.  
  1670. static ap_Bool
  1671. /*FCN*/evalu_pt_on_curve(einfo, u, pt)
  1672.   ap_Edgeinfo *einfo;
  1673.   ads_real    u;
  1674.   ads_point   pt;
  1675.  
  1676. {
  1677.     ap_Bool  status;
  1678.  
  1679.     switch(einfo->ctype) {
  1680.     case AP_LINE:
  1681.         pt[X] = 0.0;
  1682.         pt[Y] = 0.0;
  1683.         pt[Z] = u;
  1684.         status = TRUE;
  1685.         break;
  1686.  
  1687.     case AP_ELLIPSE:
  1688.         pt[X] = einfo->curve.ell.ru * cos(u);
  1689.         pt[Y] = einfo->curve.ell.rv * sin(u);
  1690.         pt[Z] = 0.0;
  1691.         status = TRUE;
  1692.         break;
  1693.  
  1694.     case AP_HYPERBOLA:
  1695.         if(fabs(u) < EPSILON)
  1696.             status = FALSE;
  1697.  
  1698.         pt[X] = einfo->curve.hyp.a * (u - 1/u) / 2.0;
  1699.         pt[Y] = einfo->curve.hyp.b * (u + 1/u) / 2.0;
  1700.         pt[Z] = 0.0;
  1701.         status = TRUE;
  1702.         break;
  1703.  
  1704.     case AP_PARABOLA:
  1705.         pt[X] = u;
  1706.         pt[Y] = u*u / einfo->curve.par.fourp;
  1707.         pt[Z] = 0.0;
  1708.         status = TRUE;
  1709.         break;
  1710. /*
  1711.     case AP_CYLCYL:
  1712.                 status = FALSE;
  1713.         break;
  1714.  
  1715.     case AP_CONCON:
  1716.                 status = FALSE;
  1717.         break;
  1718. */
  1719.  
  1720.     default:
  1721.         status = FALSE;
  1722.         break;
  1723.     }
  1724.  
  1725.     return status;
  1726.  
  1727. }
  1728.  
  1729. /*************************************************************************/
  1730. /* .doc classify_entity_membership() */
  1731. /*+
  1732.    This routine executes the command SOLCLASS
  1733.    It classifies a point or a line with respect 
  1734.    to a given object.
  1735. -*/
  1736. /*************************************************************************/
  1737.  
  1738. static void
  1739. /*FCN*/classify_entity_membership ()
  1740. {
  1741.     ap_Objid Object;
  1742.     ap_Class  pclass;
  1743.     ap_Seglist   *llist;
  1744.     ap_Edgeinfo  einfo;
  1745.     ads_name chosen;
  1746.     ads_point  pt, pc, pc1, pc2, loc;
  1747.     int   stat, status, which;
  1748.     char  inbuf[80];
  1749.  
  1750.     /* Initialize API */
  1751.  
  1752.     stat = ap_init();
  1753.     if (stat != AP_NORMAL)
  1754.         goto Error0;
  1755.  
  1756.     stat = select_object(&Object, chosen, loc);
  1757.     if(stat == FALSE)
  1758.         goto Error0;
  1759.  
  1760.     /* Highlight the selected entity */
  1761.  
  1762.     ads_redraw(chosen, 3);
  1763.  
  1764.  
  1765.     ads_initget(0, /*MSG84*/"Line Point");
  1766.     strcpy(inbuf, "");
  1767.  
  1768.     status = ads_getkword
  1769.              (/*MSG85*/"\nLine/<Point>: ", inbuf);
  1770.  
  1771.     if (status == RTNORM)
  1772.     {
  1773.         if (strcmp( /*MSG86*/"Line", inbuf ) == 0)
  1774.             which = LINE;
  1775.         else if (strcmp( /*MSG87*/"Point", inbuf ) == 0)
  1776.             which = POINT;
  1777.         else
  1778.             goto Error1;
  1779.     }
  1780.  
  1781.     if(status == RTNONE)
  1782.         which = POINT;
  1783.  
  1784.     if (status == RTCAN)
  1785.         goto Error1;
  1786.  
  1787.     switch (which)
  1788.     {
  1789.     case  POINT:
  1790.         {
  1791.             set_point(0.0, 0.0, 0.0, pt);
  1792.             stat = ads_getpoint(NULL, /*MSG88*/"\nPoint <0,0,0>:", pt);
  1793.             if ((stat == RTCAN) || (stat == RTERROR))
  1794.                 goto Error1;
  1795.  
  1796.             trans_uc2wc(pt, FALSE, pc);
  1797.             stat = ap_class_pt(Object, pc, &pclass);
  1798.             print_pt_class(pc, pclass);
  1799.             break;
  1800.         }
  1801.  
  1802.     case  LINE:
  1803.         {
  1804.             stat = get_line_data(pc1, pc2);
  1805.             if(stat == FALSE) {
  1806.                 ads_printf(/*MSG89*/"\nUnable to get line data.");
  1807.                 goto Error1;
  1808.             }
  1809.  
  1810.             stat = make_edgeinfo_from_line(pc1, pc2, &einfo);
  1811.             if(stat == FALSE) {
  1812.                 ads_printf(/*MSG90*/"\nUnable to make edgeinfo.");
  1813.                 goto Error1;
  1814.             }
  1815.  
  1816.             /* Classify the line against the object */
  1817.  
  1818.             stat = ap_class_edge(Object, &einfo, &llist);
  1819.             if (stat != AP_NORMAL) {
  1820.                 ads_printf (/*MSG91*/"\nUnable to classify line.");
  1821.                 goto Error1;
  1822.             }
  1823.  
  1824.             print_line_class(pc1, pc2, llist);
  1825.             ap_free_seglist(llist);
  1826.             break;
  1827.         }
  1828.  
  1829.     default:
  1830.         break;
  1831.  
  1832.     }
  1833.  
  1834. Error1:
  1835.     ads_redraw(chosen, 4);
  1836.  
  1837. Error0:
  1838.     ads_retvoid();
  1839.     return;
  1840. }
  1841.  
  1842. /*************************************************************************/
  1843. /* .doc print_pt_class() */
  1844. /*+
  1845.    This routine outputs the membership class of a point 
  1846. -*/
  1847. /*************************************************************************/
  1848.  
  1849. static void
  1850. /*FCN*/print_pt_class (pt, class)
  1851.   ads_point  pt;
  1852.   ap_Class  class;
  1853. {
  1854.     ads_point  pq;
  1855.  
  1856.     trans_wc2uc(pt, FALSE, pq);
  1857.     switch(class)
  1858.     {
  1859.     case AP_OFFOBJECT:
  1860.         ads_printf(/*MSG92*/"\nPoint (%f, %f, %f) is outside the solid",
  1861.                    pq[X],pq[Y],pq[Z]);
  1862.         break;
  1863.  
  1864.     case AP_ONOBJECT:
  1865.         ads_printf(/*MSG93*/"\nPoint (%f, %f, %f) is on the solid",
  1866.                    pq[X],pq[Y],pq[Z]);
  1867.         break;
  1868.  
  1869.     case AP_INOBJECT:
  1870.         ads_printf(/*MSG94*/"\nPoint (%f, %f, %f) is inside the solid",
  1871.                    pq[X],pq[Y],pq[Z]);
  1872.         break;
  1873.  
  1874.     case AP_FAILED:
  1875.         break;
  1876.     }
  1877. }
  1878.  
  1879. /*************************************************************************/
  1880. /* .doc get_line_data() */
  1881. /*+
  1882.    This routine prompts the user to select start
  1883.    and end point for a line
  1884. -*/
  1885. /*************************************************************************/
  1886. static  ap_Bool
  1887. /*FCN*/get_line_data(p1, p2)
  1888.   ads_point  p1, p2;
  1889. {
  1890.     ads_point  pt1, pt2;
  1891.     int  stat;
  1892.  
  1893.     set_point(0.0, 0.0, 0.0, pt1);
  1894.     set_point(0.0, 0.0, 1.0, pt2);
  1895.  
  1896.     stat = ads_getpoint(NULL, /*MSG95*/"\nFrom point <0,0,0>:", pt1);
  1897.     if ((stat == RTCAN) || (stat == RTERROR))
  1898.         return FALSE;
  1899.  
  1900.     stat = ads_getpoint(pt1, /*MSG96*/"\nTo point <0,0,1>:", pt2);
  1901.     if ((stat == RTCAN) || (stat == RTERROR))
  1902.         return FALSE;
  1903.  
  1904.     stat = verify_2pts_equal(pt1, pt2);
  1905.     if(stat == TRUE)
  1906.         return FALSE;
  1907.  
  1908.     trans_uc2wc(pt1, FALSE, p1);
  1909.     trans_uc2wc(pt2, FALSE, p2);
  1910.     return TRUE;
  1911. }
  1912.  
  1913. /*************************************************************************/
  1914. /* .doc make_edgeinfo_from_line() */
  1915. /*+
  1916.    This routine converts a line into an edge format
  1917. -*/
  1918. /*************************************************************************/
  1919. static  ap_Bool
  1920. /*FCN*/make_edgeinfo_from_line(p1, p2, einfo)
  1921.   ads_point  p1, p2;
  1922.   ap_Edgeinfo  *einfo;
  1923. {
  1924.     ads_real     length;
  1925.  
  1926.     /* Initialization of edge structure einfo which will  
  1927.            be used to hold line data for classification */
  1928.  
  1929.     length = ads_distance(p1, p2);
  1930.     if(fabs(length) < EPSILON)
  1931.         return FALSE;
  1932.  
  1933.     einfo->ctype = AP_LINE;
  1934.     einfo->edge_len = length;
  1935.     einfo->s_parm = 0.0;
  1936.     einfo->e_parm = length;
  1937.  
  1938.     ap_identity(einfo->edge_rm);
  1939.  
  1940.     copy_point(p1, einfo->s_pt);
  1941.     copy_point(p2, einfo->e_pt);
  1942.     return TRUE;
  1943. }
  1944.  
  1945. /*************************************************************************/
  1946. /* .doc print_line_class() */
  1947. /*+
  1948.    This routine outputs the membership of a line
  1949.    which is defined by two points ps and pe.
  1950. -*/
  1951. /*************************************************************************/
  1952.  
  1953. static void
  1954. /*FCN*/print_line_class(ps, pe, slist)
  1955.   ads_point ps, pe;
  1956.   ap_Seglist   *slist;
  1957. {
  1958.     ap_Seglist   *seg;
  1959.     ap_Real  t1, t2;
  1960.     ads_point p1, p2, pd, pt, pt1, pt2;
  1961.     int  i;
  1962.  
  1963.     i = 0;
  1964.     combine_vector(1.0, pe, -1.0, ps, pt);
  1965.     normalize_vector(pt, pd);
  1966.  
  1967.     for(seg=slist; seg != NULL; seg=seg->segnext) {
  1968.  
  1969.         i++;
  1970.         t1 = seg->seg.s_parm;
  1971.         t2 = seg->seg.e_parm;
  1972.         combine_vector(1.0, ps, t1, pd, pt1);
  1973.         combine_vector(1.0, ps, t2, pd, pt2);
  1974.         trans_wc2uc(pt1, FALSE, p1);
  1975.         trans_wc2uc(pt2, FALSE, p2);
  1976.  
  1977.         switch(seg->seg.edge_class)
  1978.         {
  1979.         case AP_OFFOBJECT:
  1980.             ads_printf(/*MSG97*/"\nSeg#%d: OUT, <%f, %f, %f> - <%f, %f, %f>",
  1981.                        i, p1[X],p1[Y],p1[Z],p2[X],p2[Y],p2[Z]);
  1982.             ads_grdraw(p1, p2, BLUE, 0);
  1983.             break;
  1984.  
  1985.         case AP_ONOBJECT:
  1986.             ads_printf(/*MSG98*/"\nSeg#%d:  ON, <%f, %f, %f> - <%f, %f, %f>",
  1987.                        i, p1[X],p1[Y],p1[Z],p2[X],p2[Y],p2[Z]);
  1988.             ads_grdraw(p1, p2, YELLOW, 0);
  1989.             break;
  1990.  
  1991.         case AP_INOBJECT:
  1992.             ads_printf(/*MSG99*/"\nSeg#%d:  IN, <%f, %f, %f> - <%f, %f, %f>",
  1993.                        i, p1[X],p1[Y],p1[Z],p2[X],p2[Y],p2[Z]);
  1994.             ads_grdraw(p1, p2, RED, 0);
  1995.             break;
  1996.  
  1997.         case AP_FAILED:
  1998.             break;
  1999.         }
  2000.     }
  2001. }
  2002.  
  2003. /*************************************************************************/
  2004. /* .doc set_ucs_to_prindir() */
  2005. /*+
  2006.    This routine executes command SOLPRINDIR.
  2007.    It resets current ucs to locate at the centroid and 
  2008.    the principal moment directions of a given object.
  2009. -*/
  2010. /*************************************************************************/
  2011.  
  2012. static void
  2013. /*FCN*/set_ucs_to_prindir()
  2014. {
  2015.     ap_Objid Object;
  2016.     ap_Massprop     mp;
  2017.     ap_Objtype  otype;
  2018.     ads_name chosen;
  2019.     ads_point  loc, px, py, pc, po, p1, p2, p3, xd, yd, zd;
  2020.     int      stat, region_in_ucs = FALSE;
  2021.  
  2022.     /* Initialize API */
  2023.  
  2024.     stat = ap_init();
  2025.     if (stat != AP_NORMAL)
  2026.         goto Error0;
  2027.  
  2028.     stat = select_object(&Object, chosen, loc);
  2029.     if(stat == FALSE)
  2030.         goto Error0;
  2031.  
  2032.     /* Highlight the selected entity */
  2033.  
  2034.     ads_redraw(chosen, 3);
  2035.  
  2036.     /* Verify object's type: solid or region */
  2037.  
  2038.     stat = ap_get_objtype(Object, &otype);
  2039.     if(stat != AP_NORMAL) {
  2040.         ads_printf(/*MSG100*/"\nCan't retrieve object's type.");
  2041.         goto Error1;
  2042.     }
  2043.  
  2044.     if(otype == AP_REGION) {
  2045.         stat = get_region_pts(Object, p1, p2, p3);
  2046.         if(stat == TRUE) {
  2047.             turn_ucsicon(OFF);
  2048.             set_current_ucs(p1, p2, p3);
  2049.         }
  2050.     } else {
  2051.         set_point(0.0, 0.0, 0.0, p1);
  2052.         set_point(1.0, 0.0, 0.0, p2);
  2053.         set_point(0.0, 1.0, 0.0, p3);
  2054.         turn_ucsicon(OFF);
  2055.         set_current_ucs(p1, p2, p3);
  2056.     }
  2057.  
  2058.     stat = ap_get_massprop(Object, &mp);
  2059.     if(stat != AP_NORMAL) {
  2060.         ads_printf(/*MSG101*/"\nUnable to retrieve mass properties.");
  2061.         goto Error1;
  2062.     }
  2063.  
  2064.     pc[X] = mp.centroid.x;
  2065.     pc[Y] = mp.centroid.y;
  2066.     pc[Z] = mp.centroid.z;
  2067.  
  2068.     copy_point(mp.prindir[0], p1);
  2069.     copy_point(mp.prindir[1], p2);
  2070.     cross_vector(p1, p2, p3);
  2071.     normalize_vector(p3, p3);
  2072.  
  2073.     trans_uc2wc(pc, FALSE, po);
  2074.     trans_uc2wc(p1, TRUE, xd);
  2075.     trans_uc2wc(p2, TRUE, yd);
  2076.     trans_uc2wc(p3, TRUE, zd);
  2077.  
  2078.     combine_vector(1.0, po, 1.0, xd, px);
  2079.     combine_vector(1.0, po, 1.0, yd, py);
  2080.     set_current_ucs(po, px, py);
  2081.     turn_ucsicon(ORIGIN);
  2082.     turn_ucsicon(ON);
  2083.  
  2084.     ads_printf(/*MSG102*/"\nCentroid  = (%f, %f, %f)", po[X], po[Y], po[Z]);
  2085.     ads_printf(/*MSG103*/"\nNew x-dir = (%f, %f, %f)", xd[X], xd[Y], xd[Z]);
  2086.     ads_printf(/*MSG104*/"\nNew y-dir = (%f, %f, %f)", yd[X], yd[Y], yd[Z]);
  2087.     ads_printf(/*MSG105*/"\nNew z-dir = (%f, %f, %f)", zd[X], zd[Y], zd[Z]);
  2088.  
  2089. Error1:
  2090.     ads_redraw(chosen, 4);
  2091.  
  2092. Error0:
  2093.     ads_retvoid();
  2094.     return;
  2095. }
  2096.  
  2097. /*************************************************************************/
  2098. /* .doc get_region_pts() */
  2099. /*+
  2100.    This routine obtains three points on the given region. 
  2101. -*/
  2102. /*************************************************************************/
  2103.  
  2104. static ap_Bool
  2105. /*FCN*/get_region_pts(obj, po, px, py)
  2106.   ap_Objid   obj;
  2107.   ads_point  po, px, py;
  2108. {
  2109.     ap_Objinfo   oinfo;
  2110.     ap_Objid  object;
  2111.     ap_Trans3d  mat;
  2112.     ads_point p1, p2;
  2113.     int stat;
  2114.  
  2115.     /* Retrieve object information and verify that it is a region */
  2116.  
  2117.     stat = ap_get_objinfo(obj, &oinfo);
  2118.     if((stat != AP_NORMAL) || (oinfo.obj != AP_REGION)) {
  2119.         ads_printf(/*MSG106*/"\nThe selected entity is not a region.");
  2120.         return FALSE;
  2121.     }
  2122.     stat = ap_identity(mat);
  2123.     if(stat != AP_NORMAL)
  2124.         return FALSE;
  2125.     stat = ap_compose(oinfo.mat, mat, mat);
  2126.     if(stat != AP_NORMAL)
  2127.         return FALSE;
  2128.  
  2129.     /* Compose matrix through CSG tree's left child branch */
  2130.  
  2131.     while (oinfo.type == AP_BOO) {
  2132.         object = oinfo.prim.boo.op1;
  2133.         stat = ap_get_objinfo(object, &oinfo);
  2134.         if(stat != AP_NORMAL)
  2135.             return FALSE;
  2136.         stat = ap_compose(oinfo.mat, mat, mat);
  2137.         if(stat != AP_NORMAL)
  2138.             return FALSE;
  2139.     }
  2140.  
  2141.     po[X] = mat[0][3];
  2142.     po[Y] = mat[1][3];
  2143.     po[Z] = mat[2][3];
  2144.     p1[X] = mat[0][0];
  2145.     p1[Y] = mat[1][0];
  2146.     p1[Z] = mat[2][0];
  2147.     p2[X] = mat[0][1];
  2148.     p2[Y] = mat[1][1];
  2149.     p2[Z] = mat[2][1];
  2150.     combine_vector(1.0, po, 1.0, p1, px);
  2151.     combine_vector(1.0, po, 1.0, p2, py);
  2152.     return TRUE;
  2153. }
  2154. /*************************************************************************/
  2155. /* .doc set_current_ucs() */
  2156. /*+
  2157.    This routine resets current ucs by three points p1, p2 & p3.
  2158.    p1, p2 and p3 must be in WCS coordinate.
  2159. -*/
  2160. /*************************************************************************/
  2161.  
  2162. static ap_Bool
  2163. /*FCN*/set_current_ucs(p1, p2, p3)
  2164.   ads_point p1, p2, p3;
  2165. {
  2166.     int stat1, stat2, stat3, stat;
  2167.     ads_point  px, py, pz;
  2168.  
  2169.     stat1 = verify_2pts_equal (p1, p2);
  2170.     stat2 = verify_2pts_equal (p2, p3);
  2171.     stat3 = verify_2pts_equal (p3, p1);
  2172.     if ((stat1 == TRUE) || (stat2 == TRUE) || (stat3 == TRUE))
  2173.         return FALSE;
  2174.  
  2175.     trans_wc2uc(p1, FALSE, px);
  2176.     trans_wc2uc(p2, FALSE, py);
  2177.     trans_wc2uc(p3, FALSE, pz);
  2178.     command_echo_off ();
  2179.     stat = ads_command(RTSTR, /*MSG107*/"_.ucs", RTSTR, /*MSG108*/"_3",
  2180.                        RT3DPOINT, px, RT3DPOINT, py, RT3DPOINT, pz, NULL);
  2181.  
  2182.     if (stat != RTNORM)
  2183.     {
  2184.         command_echo_on ();
  2185.         return FALSE;
  2186.     }
  2187.     command_echo_on ();
  2188.     return TRUE;
  2189. }
  2190.  
  2191. /*************************************************************************/
  2192. /* .doc turn_ucsicon() */
  2193. /*+
  2194.    This routine will turn ucsicon on, off or move it to new origin
  2195. -*/
  2196. /*************************************************************************/
  2197.  
  2198. static void
  2199. /* FCN */turn_ucsicon(action)
  2200.   int action;
  2201. {
  2202.     command_echo_off ();
  2203.     if (action == ON)
  2204.         ads_command (RTSTR, /*MSG109*/"_.UCSICON", RTSTR, /*MSG110*/"_ON", NULL);
  2205.     else if(action == ORIGIN)
  2206.         ads_command (RTSTR, /*MSG111*/"_.UCSICON", RTSTR, /*MSG112*/"_ORIGIN", NULL);
  2207.     else
  2208.         ads_command (RTSTR, /*MSG113*/"_.UCSICON", RTSTR, /*MSG114*/"_OFF", NULL);
  2209.  
  2210.     command_echo_on ();
  2211. }
  2212.  
  2213. /*************************************************************************/
  2214. /* .doc draw_virtual_arrow() */
  2215. /*+
  2216.    This routine draws an arrow from pt1 toward pt2 of specified color. 
  2217.    The arrow consists of a center line and an arrowhead.
  2218.    If scale is set to TRUE, the length of the arrow is scaled 
  2219.    automatically to be about 1/5 of viewport size. 
  2220.    The arrow appears on the screen only, not in AutoCAD database.
  2221. -*/
  2222. /*************************************************************************/
  2223. static ap_Bool
  2224. /*FCN*/draw_virtual_arrow(pt1, pt2, color, scale)
  2225.   ads_point  pt1, pt2;
  2226.   int  color;
  2227.   ap_Bool scale;
  2228. {
  2229.     ads_point  pc1, norm;
  2230.     ads_real  length, len, rad, vsize;
  2231.     struct resbuf  vrb;
  2232.  
  2233.     length = ads_distance(pt1, pt2);
  2234.     if (length < EPSILON)
  2235.         return FALSE;
  2236.  
  2237.     norm[X] = (pt2[X] - pt1[X]) / length;
  2238.     norm[Y] = (pt2[Y] - pt1[Y]) / length;
  2239.     norm[Z] = (pt2[Z] - pt1[Z]) / length;
  2240.  
  2241.     if(scale == TRUE) {
  2242.         ads_getvar(/*MSG0*/"VIEWSIZE", &vrb);
  2243.         vsize = vrb.resval.rreal;
  2244.         len = 0.2 * vsize;
  2245.     } else
  2246.         len = length;
  2247.  
  2248.     rad = 0.05 * len;
  2249.  
  2250.     combine_vector(1.0, pt1, len, norm, pt2);
  2251.     combine_vector(1.0, pt1, 0.9*len, norm, pc1);
  2252.  
  2253.     draw_virtual_line(pt1, pt2, color);
  2254.     draw_virtual_arrowhead(pc1, pt2, rad, YELLOW);
  2255.     return TRUE;
  2256. }
  2257.  
  2258. /*************************************************************************/
  2259. /* .doc draw_virtual_arrowhead() */
  2260. /*+
  2261.    This routine draws an arrowhead consisting of
  2262.    a circle and 4 lines. The circle has center at pt1, 
  2263.    and is normal to the direction from pt1 toward pt2. 
  2264. -*/
  2265. /*************************************************************************/
  2266. static ap_Bool
  2267. /*FCN*/draw_virtual_arrowhead(pt1, pt2, radius, color)
  2268.   ads_point  pt1, pt2;
  2269.   ads_real   radius;
  2270.   int   color;
  2271. {
  2272.     ads_point  pe, pw, ps, pn, xdir, ydir, norm, normt;
  2273.     ads_real  len;
  2274.  
  2275.     len = ads_distance(pt1, pt2);
  2276.     if (len < EPSILON)
  2277.         return FALSE;
  2278.  
  2279.     norm[X] = (pt2[X] - pt1[X]) / len;
  2280.     norm[Y] = (pt2[Y] - pt1[Y]) / len;
  2281.     norm[Z] = (pt2[Z] - pt1[Z]) / len;
  2282.  
  2283.     get_xdir_from_zdir(norm, normt);
  2284.     normalize_vector(normt, xdir);
  2285.     cross_vector(norm, xdir, normt);
  2286.     normalize_vector(normt, ydir);
  2287.  
  2288.     combine_vector(1.0, pt1, radius, xdir, pe);
  2289.     combine_vector(1.0, pt1, -radius, xdir, pw);
  2290.     combine_vector(1.0, pt1, radius, ydir, pn);
  2291.     combine_vector(1.0, pt1, -radius, ydir, ps);
  2292.  
  2293.     draw_virtual_circle(pt1, radius, norm, color);
  2294.     draw_virtual_line(pt2, pe, color);
  2295.     draw_virtual_line(pt2, pn, color);
  2296.     draw_virtual_line(pt2, ps, color);
  2297.     draw_virtual_line(pt2, pw, color);
  2298.  
  2299.     return TRUE;
  2300.  
  2301. }
  2302.  
  2303. /*************************************************************************/
  2304. /* .doc draw_virtual_line() */
  2305. /*+
  2306.    This routine draw a line from point pt1 to pt2 in wcs
  2307.    using specified color. The line appears on the screen 
  2308.    only, not in AutoCAD database
  2309. -*/
  2310. /*************************************************************************/
  2311. static ap_Bool
  2312. /*FCN*/draw_virtual_line( pt1, pt2, color)
  2313.   ads_point pt1, pt2;
  2314.   int  color;
  2315. {
  2316.     ads_point p1, p2;
  2317.     int status;
  2318.  
  2319.     trans_wc2uc(pt1, FALSE, p1);
  2320.     trans_wc2uc(pt2, FALSE, p2);
  2321.     status = ads_grdraw(p1, p2, color, 0);
  2322.     if (status == RTNORM)
  2323.         return TRUE;
  2324.     else
  2325.         return FALSE;
  2326. }
  2327.  
  2328. /*************************************************************************/
  2329. /* .doc draw_virtual_circle() */
  2330. /*+
  2331.    This routine draws a circle of a given color at  
  2332.    specified center, radius and normal direction. 
  2333.    The circle appears on the screen only, not in
  2334.    AutoCAD database.
  2335. -*/
  2336. /*************************************************************************/
  2337. static ap_Bool
  2338. /*FCN*/draw_virtual_circle(pc, radius, norm, color)
  2339.   ads_point pc, norm;
  2340.   ads_real radius;
  2341.   int  color;
  2342. {
  2343.     int  np, i;
  2344.     ads_point  temp, xdir, ydir, p[PMAX];
  2345.     ads_real   rad, ang;
  2346.  
  2347.     if(((fabs(norm[X]) < EPSILON) &&
  2348.         (fabs(norm[Y]) < EPSILON) &&
  2349.         (fabs(norm[Z]) < EPSILON)) ||
  2350.        (fabs(radius) < EPSILON))
  2351.         return FALSE;
  2352.  
  2353.     np = 12;
  2354.     get_xdir_from_zdir(norm, temp);
  2355.     normalize_vector(temp, xdir);
  2356.     cross_vector(norm, xdir, temp);
  2357.     normalize_vector(temp, ydir);
  2358.     rad = fabs(radius);
  2359.  
  2360.     for (i=0; i<=np; i++) {
  2361.         ang = i * 2.0 * PI / np;
  2362.         temp[X] = pc[X] + rad * (cos(ang)*xdir[X] + sin(ang)*ydir[X]);
  2363.         temp[Y] = pc[Y] + rad * (cos(ang)*xdir[Y] + sin(ang)*ydir[Y]);
  2364.         temp[Z] = pc[Z] + rad * (cos(ang)*xdir[Z] + sin(ang)*ydir[Z]);
  2365.         trans_wc2uc(temp, FALSE, p[i]);
  2366.     }
  2367.  
  2368.     for (i=0; i<np; i++)
  2369.         ads_grdraw(p[i], p[i+1], color, 0);
  2370.  
  2371.     return TRUE;
  2372. }
  2373.  
  2374. /*************************************************************************/
  2375. /* .doc get_xdir_from_zdir() */
  2376. /*+
  2377.    This routine computes the x-axis direction from given 
  2378.    z-axis direction based on arbitrary axis algorithm.
  2379. -*/
  2380. /*************************************************************************/
  2381. static ap_Bool
  2382. /*FCN*/get_xdir_from_zdir (zdir, xdir)
  2383.   ads_point  zdir, xdir;
  2384. {
  2385.     ads_point  u, v, wydir, wzdir;
  2386.  
  2387.     set_point(0.0, 1.0, 0.0, wydir);
  2388.     set_point(0.0, 0.0, 1.0, wzdir);
  2389.  
  2390.     if ((fabs (zdir[X]) < EPSILON) &&
  2391.         (fabs (zdir[Y]) < EPSILON) &&
  2392.         (fabs (zdir[Z]) < EPSILON))
  2393.         return FALSE;
  2394.     else
  2395.     {
  2396.         normalize_vector(zdir, u);
  2397.  
  2398.         if ((fabs(u[X]) < 1.0/64.0) && (fabs (u[Y]) < 1.0/64.0))
  2399.             cross_vector (wydir, u, v);
  2400.  
  2401.         else
  2402.             cross_vector (wzdir, u, v);
  2403.  
  2404.         normalize_vector(v, xdir);
  2405.         return TRUE;
  2406.     }
  2407. }
  2408.  
  2409. /*************************************************************************/
  2410. /* .doc copy_point() */
  2411. /*+
  2412.     This routine copies a new point pt2 from old point pt1. 
  2413. -*/
  2414. /*************************************************************************/
  2415.  
  2416. static void
  2417. /*FCN*/copy_point (pt1, pt2)
  2418.   ads_point  pt1, pt2;
  2419. {
  2420.     pt2[X] = pt1[X];
  2421.     pt2[Y] = pt1[Y];
  2422.     pt2[Z] = pt1[Z];
  2423. }
  2424.  
  2425. /*************************************************************************/
  2426. /* .doc set_point() */
  2427. /*+
  2428.     This routine assigns x, y and z coordinates to a point pt
  2429. -*/
  2430. /*************************************************************************/
  2431.  
  2432. static void
  2433. /*FCN*/set_point (x, y, z, pt)
  2434.   ads_real  x, y, z;
  2435.   ads_point  pt;
  2436. {
  2437.     pt[X] = x;
  2438.     pt[Y] = y;
  2439.     pt[Z] = z;
  2440. }
  2441.  
  2442. /*************************************************************************/
  2443. /* .doc verify_2pts_equal() */
  2444. /*+
  2445.    This routine verifies whether two points p1 & p2 are equal or not.
  2446. -*/
  2447. /*************************************************************************/
  2448.  
  2449. static ap_Bool
  2450. /* FCN */verify_2pts_equal (p1, p2)
  2451.   ads_point  p1, p2;
  2452. {
  2453.     ads_real   dx, dy, dz;
  2454.  
  2455.     dx = fabs (p2[X] - p1[X]);
  2456.     dy = fabs (p2[Y] - p1[Y]);
  2457.     dz = fabs (p2[Z] - p1[Z]);
  2458.  
  2459.  
  2460.     if ((dx < EPSILON) && (dy < EPSILON) && (dz < EPSILON))
  2461.         return TRUE;
  2462.     else
  2463.         return FALSE;
  2464. }
  2465.  
  2466. /*************************************************************************/
  2467. /* .doc combine_vector() */
  2468. /*+
  2469.     This routine perform linear combination of two vectors. 
  2470.         p3 = a . p1 + b . p2;
  2471. -*/
  2472. /*************************************************************************/
  2473.  
  2474. static void
  2475. /*FCN*/combine_vector(a, p1, b, p2, p3)
  2476.   ads_real  a, b;
  2477.   ads_point p1, p2, p3;
  2478. {
  2479.     p3[X] = a * p1[X] + b * p2[X];
  2480.     p3[Y] = a * p1[Y] + b * p2[Y];
  2481.     p3[Z] = a * p1[Z] + b * p2[Z];
  2482. }
  2483.  
  2484. /*************************************************************************/
  2485. /* .doc normalize_vector() */
  2486. /*+
  2487.    This routine normalizes a vector, that is q = p/||p||
  2488. -*/
  2489. /*************************************************************************/
  2490.  
  2491. static ap_Bool
  2492. /*FCN*/normalize_vector (p, q)
  2493.   ads_point  p, q;
  2494. {
  2495.     ap_Real temp, dis;
  2496.  
  2497.     temp = p[X]*p[X] + p[Y]*p[Y] + p[Z]*p[Z];
  2498.     if (temp < EPSILON * EPSILON)
  2499.         return FALSE;
  2500.  
  2501.     dis = sqrt (temp);
  2502.     q[X] = p[X] / dis;
  2503.     q[Y] = p[Y] / dis;
  2504.     q[Z] = p[Z] / dis;
  2505.     return TRUE;
  2506. }
  2507.  
  2508. /*************************************************************************/
  2509. /* .doc cross_vector() */
  2510. /*+
  2511.     This routine conducts the cross product of two vectors.  
  2512. -*/
  2513. /*************************************************************************/
  2514.  
  2515. static void
  2516. /*FCN*/cross_vector(ap, bp, cp)
  2517.   ads_point ap, bp, cp;
  2518. {
  2519.     ads_point result;
  2520.  
  2521.     result[X] = ap[Y] * bp[Z] - ap[Z] * bp[Y];
  2522.     result[Y] = ap[Z] * bp[X] - ap[X] * bp[Z];
  2523.     result[Z] = ap[X] * bp[Y] - ap[Y] * bp[X];
  2524.     copy_point (result, cp);
  2525. }
  2526.  
  2527. /*************************************************************************/
  2528. /* .doc trans_pt_by_matrix() */
  2529. /*+
  2530.     This routine transforms a point pin to pout by the matrix m.  
  2531. -*/
  2532. /*************************************************************************/
  2533. static void
  2534. /*FCN*/trans_pt_by_matrix(m, pin, pout)
  2535.   ap_Trans3d m;
  2536.   ads_point pin, pout;
  2537. {
  2538.     register i;
  2539.     ads_real sum[3];
  2540.  
  2541.     for (i = 0; i < 3; i++)
  2542.         sum[i] = m[i][0] * pin[X] +
  2543.                  m[i][1] * pin[Y] +
  2544.                  m[i][2] * pin[Z] +
  2545.                  m[i][3];
  2546.     pout[X] = sum[0];
  2547.     pout[Y] = sum[1];
  2548.     pout[Z] = sum[2];
  2549. }
  2550.  
  2551. /*************************************************************************/
  2552. /* .doc trans_uc2wc() */
  2553. /*+
  2554.    This routine transforms a point p in ucs into a point q in wcs.
  2555.    If vec = TRUE, then p is a vector
  2556.    If vec = FALSE, then p is a point
  2557. -*/
  2558. /*************************************************************************/
  2559.  
  2560. static void
  2561. /*FCN*/trans_uc2wc(p,vec,q)
  2562.   ads_point p, q;
  2563.   ap_Bool vec;
  2564. {
  2565.     struct resbuf rbfrom, rbto;
  2566.  
  2567.     rbfrom.restype = RTSHORT;
  2568.     rbto.restype = RTSHORT;
  2569.     rbfrom.resval.rint = 1;           /* from ucs */
  2570.     rbto.resval.rint = 0;             /* to world */
  2571.     ads_trans(p, &rbfrom, &rbto, vec, q);
  2572. }
  2573.  
  2574. /*************************************************************************/
  2575. /* .doc trans_wc2uc() */
  2576. /*+
  2577.    This routine transforms a point p in wcs into a point q in ucs
  2578.    If vec = TRUE, then p is a vector
  2579.    If vec = FALSE, then p is a point
  2580. -*/
  2581. /*************************************************************************/
  2582.  
  2583. static void
  2584. /*FCN*/trans_wc2uc(p,vec,q)
  2585.   ads_point p, q;
  2586.   ap_Bool vec;
  2587. {
  2588.     struct resbuf rbfrom, rbto;
  2589.  
  2590.     rbfrom.restype = RTSHORT;
  2591.     rbto.restype = RTSHORT;
  2592.     rbfrom.resval.rint = 0;           /* from world */
  2593.     rbto.resval.rint = 1;             /* to ucs */
  2594.     ads_trans(p, &rbfrom, &rbto, vec, q);
  2595. }
  2596.  
  2597. /*************************************************************************/
  2598. /* .doc find_minimum() */
  2599. /*+
  2600.    This routine finds the minimum value in array[] containing
  2601.    nt real number.  It returns both the minimum value and the index.
  2602. -*/
  2603. /*************************************************************************/
  2604. static ads_real
  2605. /*FCN*/find_minimum (array, nt, index)
  2606.   ads_real  array[];
  2607.   int       nt, *index;
  2608. {
  2609.     ads_real  minimum;
  2610.     int  i;
  2611.  
  2612.     minimum = array[0];
  2613.     *index = 0;
  2614.     for (i=0; i<nt; i++)
  2615.     {
  2616.         if (array[i] < minimum)
  2617.         {
  2618.             minimum = array[i];
  2619.             *index = i;
  2620.         }
  2621.     }
  2622.     return (minimum);
  2623. }
  2624.  
  2625. /* EOF */
  2626.