home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 13 / 13.iso / p / p024 / 16.img / AME3.LIB / DRILL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-17  |  35.2 KB  |  1,188 lines

  1. /* Next available MSG number is 34 */
  2.  
  3. /************************************************************************
  4. Name: drill.c.  AME2_APLIB_SAMP_drill.c
  5.  
  6. Description: AME/API sample program for drilling hole 
  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. *    This program allows the user to drill hole on the selected face     * 
  29. *    of a given object at the specified center, diameter, and depth.     *
  30. *                                                                        *
  31. *    The command syntax is shown as follows:                             *
  32. *                                                                        *
  33. *         Command:  soldrill                                             *
  34. *         Select a face:  Pick a face                                    *
  35. *         Center:  Pick a point                                          *
  36. *         Diameter <1.0>:  Enter a value                                 *
  37. *         Depth <through>:  Enter a value or RETURN for through hole     *
  38. *                                                                        *
  39. *    If user enters a value for a known depth, the hole will be drilled  *
  40. *    from the selected face, along the face normal direction and         *
  41. *    terminating at the specified depth.  If user selects through        *
  42. *    option, the minimum depth required for drilling a through hole      *
  43. *    will be determined by the program automatically.  If any free face  *
  44. *    is detected before through hole can be completed, user will be      *
  45. *    notified and prompted for whether to stop drilling at the first     *
  46. *    encountered free face.                                              *
  47. *                                                                        *
  48. *    In current implementation, only plane faces and normal drilling     *
  49. *    are supported.  Users can easily extend or tailor this sample       *
  50. *    program to fit his or her own need.                                 *
  51. *                                                                        *
  52. *    To run the program, You have to xload the executable code "drill"   *
  53. *    Then enter the command "soldrill" at regular AutoCAD prompt         *
  54. *                                                                        *
  55. *    command: soldrill                                                   *
  56. *                                                                        *
  57. **************************************************************************
  58.  
  59.  
  60. Modification history:
  61.     Refer to the RCS section at the end of this file.
  62.  
  63. Bugs and restrictions on use:
  64.  
  65. Notes:
  66.  
  67. **************************************************************************/
  68.  
  69.  
  70. /*************************************************************************/
  71. /* Includes */
  72. /*************************************************************************/
  73.  
  74. #include <stdio.h>
  75. #include <string.h>
  76. #include <math.h>
  77. #include <adslib.h>
  78. #include <aplib.h>
  79.  
  80. /*************************************************************************/
  81. /* Defines */
  82. /*************************************************************************/
  83.  
  84. #define  PI   3.14159265358927
  85. #define  EPSILON  1.0e-8
  86. #define  OFF      0
  87. #define  ON       1
  88. #define  ORIGIN   2
  89. #define  NO       0
  90. #define  YES      1
  91. #define  CANCEL  -1
  92. #define  NRAY    17
  93.  
  94. #ifndef ELEMENTS
  95. #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
  96. #endif
  97.  
  98. /*************************************************************************/
  99. /* Typedefs */
  100. /*************************************************************************/
  101.  
  102.  
  103. /*************************************************************************/
  104. /* Global variables */
  105. /*************************************************************************/
  106.  
  107. /* Function type declaration */
  108.  
  109. int      funcload();
  110. void     print_new_command_set();
  111. void     command_echo_off();
  112. void     command_echo_on();
  113. void     drill_hole_func();
  114. ap_Bool  get_hole_data();
  115. void     turn_ucsicon();
  116. ap_Bool  get_pts_from_face();
  117. void     copy_point();
  118. ap_Bool  verify_2pts_equal();
  119. void     get_current_ucs();
  120. ap_Bool  set_current_ucs();
  121. void     trans_wc2uc();
  122. void     trans_uc2wc();
  123. void     add_vector();
  124. void     sub_vector();
  125. void     cross_vector();
  126. ads_real dot_vector();
  127. ap_Bool  normalize_vector();
  128. ap_Bool  find_through_hole_depth();
  129. ap_Real  find_maximum();
  130. ap_Real  find_minimum();
  131. void     get_model_extend();
  132. int      get_yesno_from_user();
  133. ap_Bool  verify_planes_equal();
  134.  
  135.  
  136. struct resbuf  Echo1, Echo2;
  137.  
  138. /* Command definition and dispatch table.  */
  139.  
  140. struct ads_comm {
  141.     char   *cmdname;
  142.     void   (*cmdfunc) ();
  143. };
  144.  
  145. struct ads_comm cmdtab[] = {
  146.  
  147.      {/*MSG1*/"C:SOLDRILL", drill_hole_func},
  148.     };
  149.  
  150. /*************************************************************************/
  151. /* .doc main() */
  152. /*+
  153. -*/
  154. /*************************************************************************/
  155.  
  156. void
  157. /*FCN*/main(argc, argv)
  158.   int             argc;
  159.   char           *argv[];
  160. {
  161.     int             stat, cindex;
  162.     short           scode = 1;
  163.  
  164.     ads_init(argc, argv);
  165.  
  166.     while (TRUE) {
  167.         if ((stat = ads_link(scode)) < 0) {
  168.             printf(/*MSG2*/"DRILL: bad status from ads_link() = %d\n",
  169.                    stat);
  170.             fflush(stdout);
  171.             ads_exit(1);
  172.         }
  173.         scode = -RSRSLT;
  174.  
  175.         switch (stat) {
  176.  
  177.         case RQXLOAD:                 /* Load & register functions */
  178.             scode = -(funcload() ? RSRSLT : RSERR);
  179.             scode = -RSRSLT;
  180.             print_new_command_set();
  181.             break;
  182.  
  183.         case RQSUBR:                  /* Evaluate external lisp function */
  184.             cindex = ads_getfuncode();
  185.             (*cmdtab[cindex].cmdfunc) ();
  186.             break;
  187.  
  188.         case RQXUNLD:                 /* Unloading */
  189.             ads_printf (/*MSG3*/"Unloading: ");
  190.             break;
  191.  
  192.         case RQSAVE:                  /* AutoCAD SAVE notification */
  193.             break;
  194.  
  195.         case RQQUIT:                  /* AutoCAD QUIT notification */
  196.             break;
  197.  
  198.         case RQEND:                   /* AutoCAD END notification */
  199.             break;
  200.  
  201.         default:
  202.             break;
  203.  
  204.         }
  205.  
  206.     }
  207. }
  208.  
  209. /*************************************************************************/
  210. /* .doc funcload() */
  211. /*+
  212.    Load external functions into AutoCAD system
  213. -*/
  214. /*************************************************************************/
  215.  
  216. static int 
  217. /*FCN*/funcload()
  218.  
  219. {
  220.     int             i;
  221.  
  222.     for (i = 0; i < ELEMENTS(cmdtab); i++) {
  223.         if(! ads_defun (cmdtab[i].cmdname , i))
  224.             return  RTERROR;
  225.     }
  226.     return RTNORM;
  227. }
  228.  
  229. /*************************************************************************/
  230. /* .doc print_new_command_set() */
  231. /*+
  232. -*/
  233. /*************************************************************************/
  234.  
  235. static  void
  236. /*FCN*/print_new_command_set()
  237. {
  238.     ads_printf(/*MSG4*/"\nNew loaded command: SOLDRILL\n");
  239. }
  240.  
  241.  
  242. /*************************************************************************/
  243. /* .doc command_echo_off() */
  244. /*+
  245.    Suppress command echo
  246. -*/
  247. /*************************************************************************/
  248.  
  249. static void
  250. /*FCN*/command_echo_off()
  251. {
  252.     ads_getvar (/*MSG0*/"CMDECHO", &Echo1);
  253.     Echo2.restype = RTSHORT;
  254.     Echo2.resval.rint = FALSE;
  255.     ads_setvar (/*MSG0*/"CMDECHO", &Echo2);
  256. }
  257.  
  258. /*************************************************************************/
  259. /* .doc command_echo_on() */
  260. /*+
  261.    Resume command echo
  262. -*/
  263. /*************************************************************************/
  264.  
  265. static void
  266. /*FCN*/command_echo_on()
  267. {
  268.     ads_setvar (/*MSG0*/"CMDECHO", &Echo1);
  269. }
  270.  
  271. /*************************************************************************/
  272. /* .doc drill_hole_func() */
  273. /*+
  274.    This routine performs the following tasks:
  275.  
  276.    1.  Prompt the user to select a face from existing object.
  277.            Only plane face will be accepted.
  278.    2.  Verify whether the selected face lies in current ucs plane.
  279.    3.  If "NO", store current ucs in matrix and set new ucs to 
  280.            align with the selected face. 
  281.    4.  Prompt user to select center, diameter and depth for the hole.
  282.    5.  If the picked center point doesn't locate on the selected face,
  283.            project it onto the face.
  284.    6.  If through hole is desired, calculate the minimum depth 
  285.            required for drilling a through hole.
  286.    7.  Create a cylindrical drilling tool and align it with 
  287.            the desired hole's position and orientation.
  288.    8.  Subtract cylinder from the selected object to create a hole
  289. -*/
  290. /*************************************************************************/
  291.  
  292. static void
  293. /*FCN*/drill_hole_func()
  294. {
  295.     ap_Real  diameter, depth, radius;
  296.     ap_Trans3d  m;
  297.     ap_Objid object, cyl, result;
  298.     ap_Featid face;
  299.     ads_point  p1, p2, p3, pc, pt;
  300.     ads_point  porg, px, py, xdir, ydir, zdir;
  301.     ads_point  pts[3], pnorm, normal;
  302.     ap_Class pclass;
  303.     int stat;
  304.     ap_Bool  reset_ucs = FALSE, through_hole = FALSE;
  305.  
  306.     /* Initialize API */
  307.  
  308.     stat = ap_init();
  309.     if (stat != AP_NORMAL)
  310.         goto Error1;
  311.  
  312.     /* Prompt user to select a face */
  313.  
  314.     stat = ap_sel_face (/*MSG5*/"\nSelect a planar face to drill the hole:\n",
  315.                         &object, &face);
  316.     if (stat != AP_NORMAL) {
  317.         ads_printf(/*MSG6*/"\nUnable to get the face.");
  318.         goto Error1;
  319.     }
  320.  
  321.     /* Retrieve three points p1, p2, p3 on the face and 
  322.        inward normal vector to the plane */
  323.  
  324.     stat = get_pts_from_face (object, face, p1, p2, p3, normal);
  325.     if (stat == FALSE)
  326.         goto Error1;
  327.  
  328.     /* Retrieve current ucs's origin, x-direction & y-direction */
  329.  
  330.     get_current_ucs (porg, xdir, ydir);
  331.     cross_vector(xdir, ydir, zdir);
  332.     normalize_vector(zdir, pnorm);
  333.  
  334.     /* Verify whether selected face lies in current ucs plane. 
  335.        If not, set new ucs to align with the selected face
  336.        and move the ucsicon to new origin */
  337.  
  338.     stat = verify_planes_equal(porg, pnorm, p1, normal);
  339.     if(stat == FALSE) {
  340.         set_current_ucs (p1, p2, p3);
  341.         turn_ucsicon(ORIGIN);
  342.         reset_ucs = TRUE;
  343.     }
  344.  
  345.     /* Prompt user for selection of center, diameter and depth */
  346.  
  347.     stat = get_hole_data(pt, &diameter, &depth);
  348.     if (stat == FALSE) {
  349.         goto Error2;
  350.     } else if (depth < 0.0) {
  351.         through_hole = TRUE;
  352.     }
  353.  
  354.     radius = diameter / 2.0;
  355.  
  356.     /* Project point pt to the ucs plane of the selected face */
  357.  
  358.     pt[Z] = 0.0;
  359.  
  360.     /* Transform point pt from ucs to wcs coordinate */
  361.  
  362.     trans_uc2wc(pt, FALSE, pc);
  363.  
  364.     /* Check whether point pc locate inside the object */
  365.  
  366.     stat = ap_class_pt (object, pc, &pclass);
  367.     if ((stat != AP_NORMAL) || (pclass == AP_INOBJECT)) {
  368.         ads_printf(/*MSG7*/"\nInvalid center point.\n");
  369.         goto Error2;
  370.     }
  371.  
  372.     /* Compute the through hole depth */
  373.  
  374.     if (through_hole == TRUE) {
  375.         stat=find_through_hole_depth(object, normal, pc, radius, &depth);
  376.         if (stat == FALSE) {
  377.             ads_printf(/*MSG8*/"\nUnable to find through hole depth.\n");
  378.             goto Error2;
  379.         }
  380.     }
  381.  
  382.     /* Create a cylindrical tool to drill the hole */
  383.  
  384.     stat = ap_cylinder (radius, radius, depth, &cyl);
  385.     if (stat != AP_NORMAL) {
  386.         ads_printf(/*MSG9*/"\nUnable to create cylinder to drill hole.\n");
  387.         goto Error2;
  388.     }
  389.  
  390.     /* Move the tool and align it with the planed hole location */
  391.  
  392.     copy_point(pc, pts[0]);
  393.     add_vector(pts[0], normal, pts[1]);
  394.     ap_pts2xfm(pts, 2, m);
  395.     ap_move_obj (cyl, m, TRUE);
  396.  
  397.     /* Subtract cylinder tool from the selected object */
  398.  
  399.     stat = ap_subtract (object, cyl, &result);
  400.     if (stat != AP_NORMAL) {
  401.         ads_printf(/*MSG10*/"\nUnable to drill hole.\n");
  402.         goto Error2;
  403.     }
  404.  
  405.     /* Display the result object on the screen */
  406.  
  407.     ap_post_obj (result, AP_POSTWIRE);
  408.  
  409.     /* Restore ucs back to original location before drilling */
  410.  
  411. Error2:
  412.     if(reset_ucs == TRUE) {
  413.         add_vector(porg, xdir, px);
  414.         add_vector(porg, ydir, py);
  415.         set_current_ucs (porg, px, py);
  416.     }
  417. Error1:
  418.     ads_retvoid();
  419.     return;
  420. }
  421.  
  422. /*************************************************************************/
  423. /* .doc get_hole_data() */
  424. /*+
  425.    This routine prompts the user to enter hole data.
  426. -*/
  427. /*************************************************************************/
  428. static ap_Bool
  429. /*FCN*/get_hole_data (pc, dia, depth)
  430.   ads_point  pc;
  431.   ads_real   *dia, *depth;
  432. {
  433.     int  stat;
  434.  
  435.     /* Initialization of wheel data for default input */
  436.  
  437.     pc[X]  = 0.0;
  438.     pc[Y]  = 0.0;
  439.     pc[Z]  = 0.0;
  440.     *dia   = 1.0;
  441.     *depth = 1.0;
  442.  
  443.     /* Acquire values of parameters associated with hole  
  444.        from the user and verify the validity of input data */
  445.  
  446.     stat = ads_getpoint (NULL, /*MSG11*/"\nCenter <0,0,0>: ", pc);
  447.     if (stat == RTCAN) {
  448.         return FALSE;
  449.     }
  450.  
  451.     stat = ads_getreal (/*MSG12*/"\nDiameter <1.0>: ", dia);
  452.     if (stat == RTCAN) {
  453.         return FALSE;
  454.     } else if (*dia <= 0.0) {
  455.         ads_printf(/*MSG13*/"\nValue must be positive and nonzero.");
  456.         return FALSE;
  457.     }
  458.  
  459.     stat = ads_getreal (/*MSG14*/"\nDepth <through>: ", depth);
  460.     if (stat == RTCAN) {
  461.         return FALSE;
  462.     } else if (stat == RTNONE) {
  463.         *depth = -1.0;
  464.     } else if (*depth <= 0.0) {
  465.         ads_printf(/*MSG15*/"\nValue must be positive and nonzero.");
  466.         return FALSE;
  467.     }
  468.  
  469.     return TRUE;
  470. }
  471.  
  472. /*************************************************************************/
  473. /* .doc turn_ucsicon() */
  474. /*+
  475.    This routine will turn ucsicon on, off or move it to new origin
  476. -*/
  477. /*************************************************************************/
  478.  
  479. static void
  480. /* FCN */turn_ucsicon(action)
  481.   int action;
  482. {
  483.     command_echo_off ();
  484.     if (action == ON)
  485.         ads_command (RTSTR, /*MSG16*/"_.UCSICON", RTSTR, /*MSG17*/"_ON", NULL);
  486.     else if(action == ORIGIN)
  487.         ads_command (RTSTR, /*MSG18*/"_.UCSICON", RTSTR, /*MSG19*/"_ORIGIN", NULL);
  488.     else
  489.         ads_command (RTSTR, /*MSG20*/"_.UCSICON", RTSTR, /*MSG21*/"_OFF", NULL);
  490.  
  491.     command_echo_on ();
  492. }
  493.  
  494. /*************************************************************************/
  495. /* .doc get_pts_from_face() */
  496. /*+
  497.    This routine performs the following tasks:
  498.  
  499.    1.  Verify that the selected face is a planar face.
  500.    2.  Retrieve the origin of the face coordinate system (pt1).
  501.    3.  Retrieve the x-direction of the face coordinate system.
  502.    4.  Retrieve the y-direction of the face coordinate system.
  503.    5.  Retrieve the inward face normal direction (norm).
  504.    6.  Compute pt2 and pt3.
  505. -*/
  506. /*************************************************************************/
  507.  
  508. static ap_Bool
  509. /*FCN*/get_pts_from_face(object, face, pt1, pt2, pt3, norm)
  510.   ap_Objid  object;
  511.   ap_Featid  face;
  512.   ads_point  pt1, pt2, pt3, norm;
  513. {
  514.     ads_point  px, py;
  515.     ap_Faceinfo  *finfo;
  516.     int  stat;
  517.  
  518.     /* Retrieve face type and verify whether it is planar */
  519.  
  520.     stat = ap_get_faceinfo(object, face, &finfo);
  521.     if (stat != AP_NORMAL) {
  522.         ads_printf (/*MSG22*/"\nUnable to retrieve face information.");
  523.         ads_retvoid();
  524.         return FALSE;
  525.     }
  526.     if (finfo->stype != AP_PLANAR) {
  527.         ads_printf (/*MSG23*/"\nThe selected face must be planar.");
  528.         ads_retvoid();
  529.         return FALSE;
  530.     }
  531.  
  532.     /* Retrieve the origin of the face coordinate system */
  533.  
  534.     pt1[X] = finfo->face_rm[0][3];
  535.     pt1[Y] = finfo->face_rm[1][3];
  536.     pt1[Z] = finfo->face_rm[2][3];
  537.  
  538.     /* Retrieve x-direction of the face coordinate system */
  539.  
  540.     px[X]  = finfo->face_rm[0][0];
  541.     px[Y]  = finfo->face_rm[1][0];
  542.     px[Z]  = finfo->face_rm[2][0];
  543.  
  544.     /* Retrieve y-direction of the face coordinate system */
  545.  
  546.     py[X]  = finfo->face_rm[0][1];
  547.     py[Y]  = finfo->face_rm[1][1];
  548.     py[Z]  = finfo->face_rm[2][1];
  549.  
  550.     /* Retrieve inward face normal direction */
  551.  
  552.     norm[X]  = - finfo->surf.pla.norm[X];
  553.     norm[Y]  = - finfo->surf.pla.norm[Y];
  554.     norm[Z]  = - finfo->surf.pla.norm[Z];
  555.     add_vector(pt1, px, pt2);
  556.     add_vector(pt1, py, pt3);
  557.     ap_free_faceinfo(finfo);
  558.     return TRUE;
  559. }
  560.  
  561. /*************************************************************************/
  562. /* .doc copy_point() */
  563. /*+
  564.     Duplicate a point, that is pt2 = pt1
  565. -*/
  566. /*************************************************************************/
  567.  
  568. static void
  569. /*FCN*/copy_point (pt1, pt2)
  570.   ads_point  pt1, pt2;
  571. {
  572.     pt2[X] = pt1[X];
  573.     pt2[Y] = pt1[Y];
  574.     pt2[Z] = pt1[Z];
  575. }
  576.  
  577. /*************************************************************************/
  578. /* .doc verify_2pts_equal() */
  579. /*+
  580.    Verify whether two points p1 & p2 are equal
  581.    that is, within tolerance EPSILON
  582. -*/
  583. /*************************************************************************/
  584.  
  585. static ap_Bool
  586. /* FCN */verify_2pts_equal (p1, p2)
  587.   ads_point  p1, p2;
  588. {
  589.     ads_real   dx, dy, dz;
  590.  
  591.     dx = fabs (p2[X] - p1[X]);
  592.     dy = fabs (p2[Y] - p1[Y]);
  593.     dz = fabs (p2[Z] - p1[Z]);
  594.  
  595.  
  596.     if ((dx < EPSILON) && (dy < EPSILON) && (dz < EPSILON))
  597.         return TRUE;
  598.     else
  599.         return FALSE;
  600. }
  601.  
  602. /*************************************************************************/
  603. /* .doc get_current_ucs() */
  604. /*+
  605.     Retrieve current ucs's origin, x-direction & y-direction.
  606.         Return them through arguments po, px & py respectively.
  607. -*/
  608. /*************************************************************************/
  609.  
  610. static void
  611. /*FCN*/get_current_ucs(po, px, py)
  612.   ads_point po, px, py;
  613.  
  614. {
  615.     struct resbuf   ucso, ucsx, ucsy;
  616.  
  617.     ads_getvar (/*MSG0*/"UCSORG", &ucso);
  618.     ads_getvar (/*MSG0*/"UCSXDIR", &ucsx);
  619.     ads_getvar (/*MSG0*/"UCSYDIR", &ucsy);
  620.  
  621.     copy_point(ucso.resval.rpoint, po);
  622.     copy_point(ucsx.resval.rpoint, px);
  623.     copy_point(ucsy.resval.rpoint, py);
  624. }
  625. /*************************************************************************/
  626. /* .doc set_current_ucs() */
  627. /*+
  628.    Reset current ucs by using three points p1, p2 & p3, where
  629.    p1 = new origin
  630.    p1p2 = new x-direction
  631.    p1p2 x p1p3 = new z-direction 
  632. -*/
  633. /*************************************************************************/
  634.  
  635. static ap_Bool
  636. /*FCN*/set_current_ucs(p1, p2, p3)
  637.   ads_point p1, p2, p3;
  638. {
  639.     ads_point pt1, pt2, pt3;
  640.     int stat1, stat2, stat3, stat;
  641.  
  642.     stat1 = verify_2pts_equal (p1, p2);
  643.     stat2 = verify_2pts_equal (p2, p3);
  644.     stat3 = verify_2pts_equal (p3, p1);
  645.     if ((stat1 == TRUE) || (stat2 == TRUE) || (stat3 == TRUE))
  646.         return FALSE;
  647.  
  648.     trans_wc2uc(p1, FALSE, pt1);
  649.     trans_wc2uc(p2, FALSE, pt2);
  650.     trans_wc2uc(p3, FALSE, pt3);
  651.  
  652.     command_echo_off ();
  653.     stat = ads_command(RTSTR, /*MSG24*/"_.ucs", RTSTR, /*MSG25*/"_3", RT3DPOINT,
  654.                        pt1, RT3DPOINT, pt2, RT3DPOINT, pt3, NULL);
  655.  
  656.     if (stat != RTNORM)
  657.     {
  658.         command_echo_on ();
  659.         return FALSE;
  660.     }
  661.     command_echo_on ();
  662.     return TRUE;
  663. }
  664.  
  665. /*************************************************************************/
  666. /* .doc trans_wc2uc() */
  667. /*+
  668.    Transform a point p in wcs into point q in ucs
  669.    If vec = TRUE, then p is a vector
  670.    If vec = FALSE, then p is a point
  671. -*/
  672. /*************************************************************************/
  673.  
  674. static void
  675. /*FCN*/trans_wc2uc(p,vec,q)
  676.   ads_point p, q;
  677.   ap_Bool vec;
  678. {
  679.     struct resbuf rbfrom, rbto;
  680.  
  681.     rbfrom.restype = RTSHORT;
  682.     rbto.restype = RTSHORT;
  683.     rbfrom.resval.rint = 0;           /* from world */
  684.     rbto.resval.rint = 1;             /* to ucs */
  685.     ads_trans(p, &rbfrom, &rbto, vec, q);
  686. }
  687.  
  688. /*************************************************************************/
  689. /* .doc trans_uc2wc() */
  690. /*+
  691.    Transform a point p in ucs into point q in wcs
  692.    If vec = TRUE, then p is a vector
  693.    If vec = FALSE, then p is a point
  694. -*/
  695. /*************************************************************************/
  696.  
  697. static void
  698. /* FCN */trans_uc2wc(p,vec,q)
  699.   ads_point p, q;
  700.   ap_Bool vec;
  701. {
  702.     struct resbuf rbfrom, rbto;
  703.  
  704.     rbfrom.restype = RTSHORT;
  705.     rbto.restype = RTSHORT;
  706.     rbfrom.resval.rint = 1;           /* from ucs */
  707.     rbto.resval.rint = 0;             /* to world */
  708.     ads_trans(p, &rbfrom, &rbto, vec, q);
  709. }
  710.  
  711. /*************************************************************************/
  712. /* .doc add_vector() */
  713. /*+
  714.     Add two vectors cp = ap + bp 
  715. -*/
  716. /*************************************************************************/
  717.  
  718. static void
  719. /*FCN*/add_vector( ap, bp, cp)
  720.   ads_point ap, bp, cp;
  721. {
  722.     cp[X] = ap[X] + bp[X];
  723.     cp[Y] = ap[Y] + bp[Y];
  724.     cp[Z] = ap[Z] + bp[Z];
  725. }
  726.  
  727. /*************************************************************************/
  728. /* .doc sub_vector() */
  729. /*+
  730.     Subtract vector bp from vector ap with result cp = ap - bp 
  731. -*/
  732. /*************************************************************************/
  733.  
  734. static void
  735. /*FCN*/sub_vector(ap, bp, cp)
  736.   ads_point ap, bp, cp;
  737. {
  738.     cp[X] = ap[X] - bp[X];
  739.     cp[Y] = ap[Y] - bp[Y];
  740.     cp[Z] = ap[Z] - bp[Z];
  741. }
  742.  
  743. /*************************************************************************/
  744. /* .doc cross_vector() */
  745. /*+
  746.     Cross product of two vectors, cp = ap X bp.  
  747. -*/
  748. /*************************************************************************/
  749.  
  750. static void
  751. /*FCN*/cross_vector(ap, bp, cp)
  752.   ads_point ap, bp, cp;
  753. {
  754.     ads_point result;
  755.  
  756.     result[X] = ap[Y] * bp[Z] - ap[Z] * bp[Y];
  757.     result[Y] = ap[Z] * bp[X] - ap[X] * bp[Z];
  758.     result[Z] = ap[X] * bp[Y] - ap[Y] * bp[X];
  759.     copy_point (result, cp);
  760. }
  761.  
  762. /*************************************************************************/
  763. /* .doc dot_vector() */
  764. /*+
  765.     Dot product of two vectors, The result = ap.bp 
  766. -*/
  767. /*************************************************************************/
  768.  
  769. static ads_real
  770. /*FCN*/dot_vector(ap, bp)
  771.   ads_point ap, bp;
  772. {
  773.     ads_real result;
  774.  
  775.     result =  ap[X] * bp[X] + ap[Y] * bp[Y] + ap[Z] * bp[Z];
  776.     return result;
  777. }
  778.  
  779. /*************************************************************************/
  780. /* .doc normalize_vector() */
  781. /*+
  782.    Normalize a vector, that is q = p/||p||
  783. -*/
  784. /*************************************************************************/
  785.  
  786. static ap_Bool
  787. /*FCN*/normalize_vector (p, q)
  788.   ads_point  p, q;
  789. {
  790.     ap_Real temp, dis;
  791.  
  792.     temp = p[X]*p[X] + p[Y]*p[Y] + p[Z]*p[Z];
  793.     if (temp < EPSILON * EPSILON)
  794.         return FALSE;
  795.  
  796.     dis = sqrt (temp);
  797.     q[X] = p[X] / dis;
  798.     q[Y] = p[Y] / dis;
  799.     q[Z] = p[Z] / dis;
  800.     return TRUE;
  801. }
  802.  
  803. /*************************************************************************/
  804. /* .doc find_through_hole_depth() */
  805. /*+
  806.    This routine performs the following tasks:
  807.  
  808.    1.  Retrieve the diagonal corners of bounding box of current 
  809.            ACAD model space.
  810.    2.  Initialize two arrays hmin[] = 0 & hmax[] = diagonal length.  
  811.    3.  Generate NRAY (17) number of sample rays of equal length (diagonal), 
  812.            starting from the selected face, toward the inside of the object,
  813.            and ending at the outside of the object.
  814.    4.  Place one ray at the center and the rest of them equally-spaced  
  815.            along the perimeter of the circle at the desired hole location.  
  816.    5.  For each ray, classify it against the selected object and
  817.            break the ray into subsegments consisting of either inside, on or
  818.            outside the object.   
  819.    6.  If none of the sample rays contains inside subsegment, we may
  820.            conclude that the selected center point pc is an invalid 
  821.            location for drilling a hole.  So set intersection = FALSE.
  822.    7.  For each ray, if it contains more than one inside subsegment,
  823.            then, the ray must have hit some free faces before it can 
  824.            completely penetrate through the object.  If all the sample rays
  825.            hit free faces before through the object, one may conclude that the 
  826.            drilling tool will encounter free faces before penetration.
  827.            If this is the case, set seperation = TRUE, otherwise, 
  828.            seperation = FALSE.
  829.    8.  For each ray, compute the length of first inside subsegment and
  830.            store the length in array element hmin[i].  Similarly, compute
  831.            the length from selected face to the beginning of the second 
  832.            inside subsegment and store the result in array element hmax[i].
  833.    9.  Obtain h1 = max {hmin[i]} and h2 = min {hmax[i]}. 
  834.    10. If seperation = TRUE, prompt the user whether to stop drilling
  835.            at next free face.  
  836.    11. If choice = YES, return either depth = h1 or depth = h2,
  837.            depending on whether interfering with other free faces or not.
  838.    12. If separation = FALSE, return depth = diagonal length.
  839. -*/
  840. /*************************************************************************/
  841.  
  842. static ap_Bool
  843. /*FCN*/find_through_hole_depth(obj, norm, pc, rad, depth)
  844.   ap_Objid  obj;
  845.   ads_point norm, pc;                 /* in wcs */
  846.   ap_Real   rad, *depth;
  847. {
  848.     ap_Edgeinfo  einfo;
  849.     ap_Seglist   *slist, *seg;
  850.     ap_Real  diagonal, angle, h1, h2, hmin[NRAY], hmax[NRAY];
  851.     ads_point pmin, pmax, pd, ps, pe, pt, pq;
  852.     int  stat, choice, i, index, ndiv;
  853.     ap_Bool  separation, intersection;
  854.  
  855.     /* Retrieve the diagonal corners of bounding box 
  856.            for current ACAD model space */
  857.  
  858.     stat = ap_obj2extents (obj, TRUE, pmin, pmax);
  859.     if (stat != AP_NORMAL) {
  860.         ads_printf (/*MSG33*/"\nUnable to get bounding box for the object.");
  861.         ads_retvoid();
  862.         return FALSE;
  863.     }
  864.  
  865.     /* Compute the length of the diagonal of the bounding box */
  866.  
  867.     diagonal = ads_distance(pmin, pmax);
  868.  
  869.     /* Initialization of arrays hmin[] & hmax[] */
  870.  
  871.     separation = TRUE;
  872.     intersection = FALSE;
  873.     for (i=0; i < NRAY; i++) {
  874.         hmin[i] = 0.0;
  875.         hmax[i] = diagonal;
  876.     }
  877.  
  878.     /* Initialization of edge structure einfo which will  
  879.            be used to hold ray data for line classification */
  880.  
  881.     einfo.ctype = AP_LINE;
  882.     einfo.edge_len = diagonal;
  883.     einfo.s_parm = 0.0;
  884.     einfo.e_parm = diagonal;
  885.     ap_identity(einfo.edge_rm);
  886.     copy_point(pc, ps);
  887.     normalize_vector(norm, pd);
  888.     ndiv = NRAY - 1;
  889.  
  890.     /* Generate a ray of diagonal length, 
  891.            starting from the hole center on the selected face, 
  892.            point toward inside of the object and,
  893.            ending at outside of the object */
  894.  
  895.     pe[X] = ps[X] + pd[X] * diagonal;
  896.     pe[Y] = ps[Y] + pd[Y] * diagonal;
  897.     pe[Z] = ps[Z] + pd[Z] * diagonal;
  898.  
  899.     copy_point(ps, einfo.s_pt);
  900.     copy_point(pe, einfo.e_pt);
  901.  
  902.     /* Classify the ray against the object */
  903.  
  904.     stat = ap_class_edge(obj, &einfo, &slist);
  905.     if (stat != AP_NORMAL) {
  906.         ads_printf (/*MSG26*/"\nUnable to classify center ray.");
  907.         ads_retvoid();
  908.         return FALSE;
  909.     }
  910.  
  911.     /* Find the length of the first subsegment which is completely
  912.            inside the object and store this length in hmin[0] */
  913.  
  914.     seg = slist;
  915.     if (seg->seg.edge_class == AP_INOBJECT) {
  916.         intersection = TRUE;
  917.         hmin[0] = seg->seg.e_parm;
  918.         seg = seg->segnext;
  919.     }
  920.  
  921.     /* Find the length of the ray from the selected face to the beginning
  922.            of the second inside subsegment and store it in hmax[0] */
  923.  
  924.     if (seg->seg.edge_class == AP_INOBJECT)
  925.         hmax[0] = seg->seg.s_parm;
  926.     else
  927.         separation = FALSE;
  928.  
  929.     /* Transform the point pc in wcs into pq in ucs, remember
  930.            that current ucs aligns with the selected face */
  931.  
  932.     trans_wc2uc(pc, FALSE, pq);
  933.  
  934.     /* Generate NRAY-1 number of sample rays of diagonal length, 
  935.            starting from the circle perimeter on the selected face, 
  936.            point toward inside of the object */
  937.  
  938.     for(i=1; i < NRAY; i++) {
  939.         angle = 2.0 * (i - 1) * PI / ndiv;
  940.         pt[X] = pq[X] + rad * cos(angle);
  941.         pt[Y] = pq[Y] + rad * sin(angle);
  942.         pt[Z] = 0.0;
  943.         trans_uc2wc(pt, FALSE, ps);
  944.  
  945.         pe[X] = ps[X] + pd[X] * diagonal;
  946.         pe[Y] = ps[Y] + pd[Y] * diagonal;
  947.         pe[Z] = ps[Z] + pd[Z] * diagonal;
  948.  
  949.         copy_point(ps, einfo.s_pt);
  950.         copy_point(pe, einfo.e_pt);
  951.  
  952.         /* Classify the ray against the object */
  953.  
  954.         stat = ap_class_edge(obj, &einfo, &slist);
  955.         if (stat != AP_NORMAL) {
  956.             ads_printf (/*MSG27*/"\nUnable to classify center ray.");
  957.             return FALSE;
  958.         }
  959.  
  960.         /* For each ray, obtain the length of the first subsegment
  961.                    that is completely inside the object and store 
  962.                this length in hmin[i] */
  963.  
  964.         seg = slist;
  965.         if (seg->seg.edge_class == AP_INOBJECT) {
  966.             intersection = TRUE;
  967.             hmin[i] = seg->seg.e_parm;
  968.             seg = seg->segnext;
  969.         }
  970.  
  971.         /* For each ray, find the length of the ray from the selected 
  972.                face to the beginning of the second inside subsegment and 
  973.                        store it in hmax[i] */
  974.  
  975.         if (seg->seg.edge_class == AP_INOBJECT)
  976.             hmax[i] = seg->seg.s_parm;
  977.         else
  978.             separation = FALSE;
  979.     }
  980.  
  981.     if(intersection == FALSE)
  982.         return FALSE;
  983.  
  984.     h1 = find_maximum(hmin, NRAY, &index);
  985.     h2 = find_minimum(hmax, NRAY, &index);
  986.  
  987.     if (separation == TRUE) {
  988.         ads_printf(/*MSG28*/"\nStop drilling at next free face, Yes/<No>: ");
  989.         choice = get_yesno_from_user(NO);
  990.         if ((choice == YES) && (h2 >= h1)) {
  991.             *depth = h1;
  992.             return TRUE;
  993.         } else if ((choice == YES) && (h2 < h1)) {
  994.             ads_printf(/*MSG29*/"\nInterference drilling.");
  995.             *depth = h2;
  996.             return TRUE;
  997.         } else if (choice == NO) {
  998.             *depth = diagonal;
  999.             return TRUE;
  1000.         } else {
  1001.             *depth = 0.0;
  1002.             return FALSE;
  1003.         }
  1004.     } else {
  1005.         *depth = diagonal;
  1006.         return TRUE;
  1007.     }
  1008. }
  1009.  
  1010. /*************************************************************************/
  1011. /* .doc find_maximum() */
  1012. /*+
  1013.    Find the maximum value among nt elements in array[].
  1014.    Return the maximum and the index associated with the maximum.
  1015. -*/
  1016. /*************************************************************************/
  1017. static ads_real
  1018. /*FCN*/find_maximum (array, nt, index)
  1019.   ads_real  array[];
  1020.   int       nt, *index;
  1021. {
  1022.     ads_real  maximum;
  1023.     int  i;
  1024.  
  1025.     maximum = array[0];
  1026.     *index = 0;
  1027.     for (i=0; i<nt; i++)
  1028.     {
  1029.         if (array[i] > maximum)
  1030.         {
  1031.             maximum = array[i];
  1032.             *index = i;
  1033.         }
  1034.     }
  1035.     return maximum;
  1036. }
  1037.  
  1038. /*************************************************************************/
  1039. /* .doc find_minimum() */
  1040. /*+
  1041.    Find the minimum value among nt elements in array[].
  1042.    Return the minimum and the index associated with the minimum.
  1043. -*/
  1044. /*************************************************************************/
  1045. static ads_real
  1046. /*FCN*/find_minimum (array, nt, index)
  1047.   ads_real  array[];
  1048.   int       nt, *index;
  1049. {
  1050.     ads_real  minimum;
  1051.     int  i;
  1052.  
  1053.     minimum = array[0];
  1054.     *index = 0;
  1055.     for (i=0; i<nt; i++)
  1056.     {
  1057.         if (array[i] < minimum)
  1058.         {
  1059.             minimum = array[i];
  1060.             *index = i;
  1061.         }
  1062.     }
  1063.     return minimum;
  1064. }
  1065.  
  1066. /*************************************************************************/
  1067. /* .doc get_model_extend() */
  1068. /*+
  1069.    Obtain the diagonal corners of bounding box of 
  1070.    current AutoCAD model space.
  1071. -*/
  1072. /*************************************************************************/
  1073. static void
  1074. /*FNC*/get_model_extend (pmin, pmax)
  1075.   ads_point  pmin, pmax;
  1076. {
  1077.     struct resbuf Emax, Emin;
  1078.  
  1079.     ads_getvar (/*MSG0*/"EXTMAX", &Emax);
  1080.     ads_getvar (/*MSG0*/"EXTMIN", &Emin);
  1081.  
  1082.     copy_point(Emin.resval.rpoint, pmin);
  1083.     copy_point(Emax.resval.rpoint, pmax);
  1084. }
  1085.  
  1086. /*************************************************************************/
  1087. /* .doc get_yesno_from_user() */
  1088. /*+
  1089.    Prompt user to choice "Yes" or "No".
  1090.    The function return "YES", "NO" or "CANCEL" depending on
  1091.    user's action and the setup for default_choice.
  1092. -*/
  1093. /*************************************************************************/
  1094. static int
  1095. /*FNC*/get_yesno_from_user (default_choice)
  1096.   ap_Bool default_choice;
  1097. {
  1098.     char  inbuf[132];
  1099.     int   status;
  1100.  
  1101.     ads_initget(0, /*MSG30*/"Yes No");
  1102.     strcpy(inbuf, "");
  1103.  
  1104.     status = ads_getkword (NULL, inbuf);
  1105.  
  1106.     if (status == RTCAN)
  1107.     {
  1108.         ads_retvoid ();
  1109.         return CANCEL;
  1110.     }
  1111.  
  1112.     else if ((default_choice == YES) && (status == RTNONE))
  1113.     {
  1114.         ads_retvoid ();
  1115.         return YES;
  1116.     }
  1117.  
  1118.     else if ((default_choice == NO) && (status == RTNONE))
  1119.     {
  1120.         ads_retvoid ();
  1121.         return NO;
  1122.     }
  1123.  
  1124.     else if (status == RTNORM)
  1125.     {
  1126.         if (strcmp (/*MSG31*/"Yes", inbuf) == 0)
  1127.         {
  1128.             ads_retvoid ();
  1129.             return YES;
  1130.         }
  1131.  
  1132.         else if (strcmp (/*MSG32*/"No", inbuf) == 0)
  1133.         {
  1134.             ads_retvoid ();
  1135.             return NO;
  1136.         }
  1137.  
  1138.         else
  1139.         {
  1140.             ads_retvoid ();
  1141.             return CANCEL;
  1142.         }
  1143.     }
  1144.  
  1145.     else
  1146.         return CANCEL;
  1147. }
  1148.  
  1149. /*************************************************************************/
  1150. /* .doc verify_planes_equal() */
  1151. /*+
  1152.    This routine verify whether two planes are coincident.
  1153.    The plane is defined by its normal and a through point.
  1154. -*/
  1155. /*************************************************************************/
  1156. static ap_Bool
  1157. /*FCN*/verify_planes_equal (org1, norm1, org2, norm2)
  1158.   ads_point  org1, norm1, org2, norm2;
  1159. {
  1160.     ads_point  dir;
  1161.     ads_real   dx, dy, dz, du, dv;
  1162.  
  1163.     if (((fabs (norm1[X]) < EPSILON) &&
  1164.          (fabs (norm1[Y]) < EPSILON) &&
  1165.          (fabs (norm1[Z]) < EPSILON)) ||
  1166.         ((fabs (norm2[X]) < EPSILON) &&
  1167.          (fabs (norm2[Y]) < EPSILON) &&
  1168.          (fabs (norm2[Z]) < EPSILON)))
  1169.         return FALSE;
  1170.  
  1171.     dx = norm1[Y]*norm2[Z] - norm1[Z]*norm2[Y];
  1172.     dy = norm1[Z]*norm2[X] - norm1[X]*norm2[Z];
  1173.     dz = norm1[X]*norm2[Y] - norm1[Y]*norm2[X];
  1174.  
  1175.     sub_vector(org2, org1, dir);
  1176.     du = dot_vector (dir, norm1);
  1177.     dv = dot_vector (dir, norm2);
  1178.  
  1179.     if ((fabs (dx) < EPSILON) && (fabs (dy) < EPSILON) &&
  1180.         (fabs (dz) < EPSILON) && (fabs (du) < EPSILON) &&
  1181.         (fabs (dv) < EPSILON))
  1182.         return TRUE;
  1183.     else
  1184.         return FALSE;
  1185. }
  1186.  
  1187. /* EOF */
  1188.