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

  1. /* Next available MSG number is 48 */
  2.  
  3. /************************************************************************
  4. Name: layout.c.  AME2_APLIB_SAMP_layout.c
  5.  
  6. Description: AME/API sample program for automatic layout of regions 
  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. *         Blanking is a typical sheet-metal forming process for mass     *
  29. *    production of parts such as gear, cam levers, etc.  The basic       *
  30. *    tools used with this manufacture process are the punch and the die. *
  31. *    The punch is the convex tool which mates with the concave die.      *
  32. *    This process often requires a layout plan of the part pattern       *
  33. *    within a given area in order to produce maximum number of parts     *
  34. *    from a given metal sheet.                                           *
  35. *                                                                        *
  36. *         This sample program illustrates how to use AME/API as          *
  37. *    development tool for creating 2D parts such as gear and sheet       *
  38. *    as regions, retrieving topological & geometric data information     *
  39. *    from the regions for reasoning & evaluation, and performing         *
  40. *    automatic layout of the part on the sheet.                          *
  41. *                                                                        *
  42. *         Three commands are available in this application, "GEAR",      *
  43. *    "SHEET" and "LAYOUT".  "GEAR" allows the user to create a 2D gear   *
  44. *    profile as sample part by specifying design parameters such as      *
  45. *    pitch circle diameter, number of teeth, and pressure angle.         *
  46. *    The gear is placed in a plane parallel to current ucs plane         *
  47. *    and is centered at the selected center point.                       *
  48. *    The command syntax for "GEAR" is shown as follows:                  *
  49. *                                                                        *
  50. *         Command: gear                                                  *
  51. *         Select center <0,0,0>: Pick a point                            *
  52. *         Enter pitch circle diameter <4.0>: Enter a value               * 
  53. *         Enter number of teeth <12>: Enter a number                     *
  54. *         Enter pressure angle <25 degrees>: Enter a value               *
  55. *                                                                        *
  56. *                                                                        *
  57. *         "SHEET" allows the user to create a 2D rectangular region      *
  58. *    as sample metal sheet by specifying parameters such as length       *
  59. *    and width.  The sheet is placed in a plane parallel to              *
  60. *    current ucs with its center at the selected center point.           *
  61. *    The command syntax for "SHEET" is shown as follows:                 *
  62. *                                                                        *
  63. *         Command: sheet                                                 *
  64. *         Select center <0,0,0>: Pick a point                            *
  65. *         Enter length <10.0>: Enter a value                             * 
  66. *         Enter width <8>: Enter a value                                 *
  67. *                                                                        *
  68. *                                                                        *
  69. *         "LAYOUT" performs automatic layout of the selected part        *
  70. *    in the selected metal sheet. It verifies the validity of the        *
  71. *    selected sheet and determines its border and size. The part is      *
  72. *    then copied and placed in the sheet, beginning from left to right   *
  73. *    and then from bottom to top until it fills up the whole sheet.      *
  74. *    It also counts the number of parts in the sheet and calculates      *
  75. *    the material utilization rate for the proposed layout. The user     *
  76. *    can experiment various layout by trying different rotation angle    *
  77. *    of the selected part with respect to the selected sheet.            *
  78. *    The command syntax for "LAYOUT" is shown as follows:                *
  79. *                                                                        *
  80. *         Command: layout                                                *
  81. *         Select a rectangular sheet: Pick a region                      *
  82. *         Select a part: Pick a region                                   *
  83. *         Rotation angle of part <0.0>:  Enter a value                   *
  84. *                                                                        *
  85. **************************************************************************
  86.  
  87.  
  88. Modification history:
  89.     Refer to the RCS section at the end of this file.
  90.  
  91. Bugs and restrictions on use:
  92.  
  93. Notes:
  94.  
  95. **************************************************************************/
  96.  
  97.  
  98. /*************************************************************************/
  99. /* Includes */
  100. /*************************************************************************/
  101.  
  102. #include <stdio.h>
  103. #include <string.h>
  104. #include <math.h>
  105. #include <adslib.h>
  106. #include <aplib.h>
  107.  
  108. /*************************************************************************/
  109. /* Defines */
  110. /*************************************************************************/
  111.  
  112. #define  PI   3.14159265358927
  113. #define  EPSILON  1.0e-8
  114. #define  PMAX     10
  115.  
  116. #ifndef ELEMENTS
  117. #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
  118. #endif
  119.  
  120. /*************************************************************************/
  121. /* Typedefs */
  122. /*************************************************************************/
  123.  
  124.  
  125. /*************************************************************************/
  126. /* Global variables */
  127. /*************************************************************************/
  128.  
  129. /* Function type declaration */
  130.  
  131. int      funcload();
  132. void     print_new_command_set();
  133. void     create_gear_func();
  134. ap_Bool  get_gear_data();
  135. void     create_sheet_func();
  136. ap_Bool  get_sheet_data();
  137. void     create_layout_func();
  138. ap_Bool  select_region();
  139. ap_Bool  define_gear_pline();
  140. ap_Bool  define_rectangle_pline();
  141. void     trans_wc2uc();
  142. void     trans_uc2wc();
  143. ap_Bool  get_region_plane();
  144. ap_Bool  verify_region_in_ucs();
  145. ap_Bool  verify_region_rectangular();
  146. ap_Bool  verify_line_horizontal();
  147. ap_Bool  verify_line_vertical();
  148. ap_Bool  insert_pt_to_array();
  149. ap_Bool  verify_2pts_equal();
  150. ads_real find_maximum();
  151. ads_real find_minimum();
  152.  
  153. /* Command definition and dispatch table.  */
  154.  
  155. struct ads_comm {
  156.     char   *cmdname;
  157.     void   (*cmdfunc) ();
  158. };
  159.  
  160. struct ads_comm cmdtab[] = {
  161.  
  162.      {/*MSG1*/"C:GEAR", create_gear_func},
  163.      {/*MSG2*/"C:SHEET", create_sheet_func},
  164.      {/*MSG3*/"C:LAYOUT", create_layout_func},
  165.     };
  166.  
  167.  
  168. /*************************************************************************/
  169. /* .doc main() */
  170. /*+
  171. -*/
  172. /*************************************************************************/
  173.  
  174. void
  175. /*FCN*/main(argc, argv)
  176.   int             argc;
  177.   char           *argv[];
  178. {
  179.     int             stat, cindex;
  180.     short           scode = 1;
  181.  
  182.     ads_init(argc, argv);
  183.  
  184.     while (TRUE) {
  185.         if ((stat = ads_link(scode)) < 0) {
  186.             printf(/*MSG4*/"LAYOUT: bad status from ads_link() = %d\n",
  187.                    stat);
  188.             fflush(stdout);
  189.             ads_exit(1);
  190.         }
  191.         scode = -RSRSLT;
  192.  
  193.         switch (stat) {
  194.  
  195.         case RQXLOAD:                 /* Load & register functions */
  196.             scode = -(funcload() ? RSRSLT : RSERR);
  197.             scode = -RSRSLT;
  198.             print_new_command_set();
  199.             break;
  200.  
  201.         case RQSUBR:                  /* Evaluate external lisp function */
  202.             cindex = ads_getfuncode();
  203.             (*cmdtab[cindex].cmdfunc) ();
  204.             break;
  205.  
  206.         case RQXUNLD:                 /* Unloading */
  207.             ads_printf (/*MSG5*/"Unloading: ");
  208.             break;
  209.  
  210.         case RQSAVE:                  /* AutoCAD SAVE notification */
  211.             break;
  212.  
  213.         case RQQUIT:                  /* AutoCAD QUIT notification */
  214.             break;
  215.  
  216.         case RQEND:                   /* AutoCAD END notification */
  217.             break;
  218.  
  219.         default:
  220.             break;
  221.  
  222.         }
  223.  
  224.     }
  225. }
  226.  
  227. /*************************************************************************/
  228. /* .doc funcload() */
  229. /*+
  230.    Load external functions into AutoCAD system
  231. -*/
  232. /*************************************************************************/
  233.  
  234. static int 
  235. /*FCN*/funcload()
  236.  
  237. {
  238.     int             i;
  239.  
  240.     for (i = 0; i < ELEMENTS(cmdtab); i++) {
  241.         if(! ads_defun (cmdtab[i].cmdname , i))
  242.             return  RTERROR;
  243.     }
  244.     return RTNORM;
  245. }
  246.  
  247. /*************************************************************************/
  248. /* .doc print_new_command_set() */
  249. /*+
  250. -*/
  251. /*************************************************************************/
  252.  
  253. static  void
  254. /*FCN*/print_new_command_set()
  255. {
  256.     ads_printf(/*MSG6*/"\nNew loaded commands:");
  257.     ads_printf(/*MSG7*/"\nGEAR, SHEET, LAYOUT\n");
  258. }
  259.  
  260. /*************************************************************************/
  261. /* .doc create_gear_func() */
  262. /*+
  263.     Creates a 2D gear parallel to current ucs plane with center at 
  264.     specified location. The gear is represented as a region.
  265. -*/
  266. /*************************************************************************/
  267.  
  268. static void
  269. /*FCN*/create_gear_func ()
  270. {
  271.     ads_point pc;
  272.     ap_Real  gear_d, alpha;
  273.     int      np, stat, number_t;
  274.     ap_Objid Gear;
  275.     ap_Swp_pts  pline[501];
  276.     ap_Trans3d  mat;
  277.  
  278.     /* Initialize API */
  279.  
  280.     stat = ap_init();
  281.     if (stat != AP_NORMAL)
  282.         goto Error;
  283.  
  284.     /* Prompt user for gear data */
  285.  
  286.     stat = get_gear_data(pc, &gear_d, &number_t, &alpha, mat);
  287.     if (stat == FALSE)
  288.         goto Error;
  289.  
  290.     /* Defines the profile for the gear boundary */
  291.  
  292.     stat = define_gear_pline(gear_d, number_t, alpha, pline, &np);
  293.     if (stat == FALSE)
  294.         goto Error;
  295.  
  296.     /* Creates a region defined by pline */
  297.  
  298.     stat = ap_polyline (np, pline, &Gear);
  299.     if (stat != AP_NORMAL)
  300.         goto Error;
  301.  
  302.     /* Move the Gear to the desired location  */
  303.  
  304.     stat = ap_move_obj(Gear, mat, FALSE);
  305.     if (stat != AP_NORMAL)
  306.         goto Error;
  307.  
  308.     /* Displays the wireframe model of the gear on the screen */
  309.  
  310.     stat = ap_post_obj (Gear, AP_POSTWIRE);
  311.     if (stat != AP_NORMAL)
  312.         goto Error;
  313.  
  314. Error:
  315.     ads_retvoid();
  316.     return;
  317.  
  318. }
  319.  
  320. /*************************************************************************/
  321. /* .doc get_gear_data() */
  322. /*+
  323.    This routine prompts the user to enter gear data.
  324. -*/
  325. /*************************************************************************/
  326. static ap_Bool
  327. /*FCN*/get_gear_data (pc, dia, nteeth, pangle, mat)
  328.   ads_point pc;
  329.   ads_real  *dia, *pangle;
  330.   int  *nteeth;
  331.   ap_Trans3d   mat;
  332. {
  333.     int  stat;
  334.     ads_point  pt, pd;
  335.     ap_Trans3d  mat1, mat2;
  336.  
  337.     /* Initialization of gear data for default input */
  338.  
  339.     pt[X] = 0.0;
  340.     pt[Y] = 0.0;
  341.     pt[Z] = 0.0;
  342.     *dia = 4.0;
  343.     *nteeth = 12;
  344.     *pangle = 25.0;
  345.  
  346.     /* Acquire values of design parameters associated with gear  
  347.        from the user and verify the validity of input data */
  348.  
  349.     stat = ads_getpoint (NULL, /*MSG8*/"\nCenter <0,0,0>: ", pt);
  350.     if (stat == RTCAN) {
  351.         return FALSE;
  352.     }
  353.     trans_uc2wc(pt, FALSE, pc);
  354.     stat = ads_getreal (/*MSG9*/"\n\nEnter pitch circle diameter <4.0>: ", dia);
  355.     if (stat == RTCAN) {
  356.         return FALSE;
  357.     } else if (*dia <= 0.0) {
  358.         ads_printf(/*MSG10*/"\nValue must be positive and nonzero.");
  359.         return FALSE;
  360.     }
  361.  
  362.     stat = ads_getint (/*MSG11*/"\nEnter number of teeth <12>: ", nteeth);
  363.     if (stat == RTCAN) {
  364.         return FALSE;
  365.     } else if (*nteeth <= 3) {
  366.         ads_printf(/*MSG12*/"\nCan not handle less than 4 teeth.");
  367.         return FALSE;
  368.     } else if (*nteeth > 36) {
  369.         ads_printf(/*MSG13*/"\nCan not handle more than 36 teeth.");
  370.         return FALSE;
  371.     }
  372.  
  373.     stat = ads_getreal (/*MSG14*/"\nEnter pressure angle <25 degrees>: ", pangle);
  374.     if (stat == RTCAN) {
  375.         return FALSE;
  376.     } else if (*pangle < 14.5) {
  377.         ads_printf(/*MSG15*/"\nAngle must be greater or equal to 14.5 degrees.");
  378.         return FALSE;
  379.     } else if (*pangle > 25.0) {
  380.         ads_printf(/*MSG16*/"\nAngle must be less or equal to 25 degrees.");
  381.         return FALSE;
  382.     }
  383.  
  384.     stat = ap_get_ucsmat(mat1);
  385.     if (stat != AP_NORMAL)
  386.         return FALSE;
  387.     trans_uc2wc(pt, TRUE, pd);
  388.     stat = ap_translate (pd[X], pd[Y], pd[Z], mat2);
  389.     if (stat != AP_NORMAL)
  390.         return FALSE;
  391.     stat = ap_compose(mat2, mat1, mat);
  392.     if (stat != AP_NORMAL)
  393.         return FALSE;
  394.     return TRUE;
  395. }
  396.  
  397. /*************************************************************************/
  398. /* .doc create_sheet_func() */
  399. /*+
  400.    Creates a rectangle parallel to current ucs plane with 
  401.    center at the selected location. The rectangle is
  402.    represented as a region.
  403. -*/
  404. /*************************************************************************/
  405.  
  406. static void
  407. /*FCN*/create_sheet_func()
  408. {
  409.     ap_Real  rect_l, rect_w;
  410.     ads_point  pc;
  411.     ap_Trans3d  mat;
  412.     int      np, stat;
  413.     ap_Objid Rect;
  414.     ap_Swp_pts  pline[5];
  415.  
  416.     /* Initialize API */
  417.  
  418.     stat = ap_init();
  419.     if (stat != AP_NORMAL)
  420.         goto Error;
  421.  
  422.     /* Prompt user for rectangular sheet data */
  423.  
  424.     stat = get_sheet_data(pc, &rect_l, &rect_w, mat);
  425.     if (stat == FALSE)
  426.         goto Error;
  427.  
  428.     /* Defines the profile for the rectangular boundary */
  429.  
  430.     stat = define_rectangle_pline(rect_l, rect_w, pline, &np);
  431.     if (stat == FALSE)
  432.         goto Error;
  433.  
  434.     /* Creates a region with boundary defined by pline */
  435.  
  436.     stat = ap_polyline (np, pline, &Rect);
  437.     if (stat != AP_NORMAL)
  438.         goto Error;
  439.  
  440.     /* Move the Sheet to the specified location */
  441.  
  442.     stat = ap_move_obj(Rect, mat, FALSE);
  443.     if (stat != AP_NORMAL)
  444.         goto Error;
  445.  
  446.     /* Displays the wireframe model of the sheet on the screen */
  447.  
  448.     stat = ap_post_obj (Rect, AP_POSTWIRE);
  449.     if (stat != AP_NORMAL)
  450.         goto Error;
  451.  
  452. Error:
  453.     ads_retvoid();
  454.     return;
  455. }
  456.  
  457. /*************************************************************************/
  458. /* .doc get_sheet_data() */
  459. /*+
  460.    This routine prompts the user to enter sheet data.
  461. -*/
  462. /*************************************************************************/
  463. static ap_Bool
  464. /*FCN*/get_sheet_data (pc, length, width, mat)
  465.   ads_point pc;
  466.   ads_real  *length, *width;
  467.   ap_Trans3d   mat;
  468. {
  469.     int  stat;
  470.     ads_point  pt, pd;
  471.     ap_Trans3d  mat1, mat2;
  472.  
  473.     /* Initialization of gear data for default input */
  474.  
  475.     pt[X] = 0.0;
  476.     pt[Y] = 0.0;
  477.     pt[Z] = 0.0;
  478.     *length = 10.0;
  479.     *width  = 8.0;
  480.  
  481.     /* Acquire values of design parameters associated with gear  
  482.        from the user and verify the validity of input data */
  483.  
  484.     stat = ads_getpoint (NULL, /*MSG17*/"\nCenter <0,0,0>: ", pt);
  485.     if (stat == RTCAN) {
  486.         return FALSE;
  487.     }
  488.     trans_uc2wc(pt, FALSE, pc);
  489.  
  490.     stat = ads_getreal (/*MSG18*/"\n\nEnter length <10.0>: ", length);
  491.     if (stat == RTCAN) {
  492.         return FALSE;
  493.     } else if (*length <= 0.0) {
  494.         ads_printf(/*MSG19*/"\nValue must be positive and nonzero.");
  495.         return FALSE;
  496.     }
  497.  
  498.     stat = ads_getreal (/*MSG20*/"\nEnter width <8.0>: ", width);
  499.     if (stat == RTCAN) {
  500.         return FALSE;
  501.     } else if (*width <= 0.0) {
  502.         ads_printf(/*MSG21*/"\nValue must be positive and nonzero.");
  503.         return FALSE;
  504.     }
  505.  
  506.     stat = ap_get_ucsmat(mat1);
  507.     if (stat != AP_NORMAL)
  508.         return FALSE;
  509.     pt[X] = pt[X] - (*length) / 2.0;
  510.     pt[Y] = pt[Y] - (*width) / 2.0;
  511.     trans_uc2wc(pt, TRUE, pd);
  512.     stat = ap_translate (pd[X], pd[Y], pd[Z], mat2);
  513.     if (stat != AP_NORMAL)
  514.         return FALSE;
  515.     stat = ap_compose(mat2, mat1, mat);
  516.     if (stat != AP_NORMAL)
  517.         return FALSE;
  518.     return TRUE;
  519. }
  520.  
  521. /*************************************************************************/
  522. /* .doc create_layout_func() */
  523. /*+
  524.    This routine performs the following tasks:
  525.  
  526.    1.  Prompt the user to select a rectangular region as metal sheet.
  527.    2.  Verify that the selected sheet lies in current ucs plane.
  528.    3.  Verify whether the selected region is a rectangular sheet
  529.           and retrieve the border and the area of the sheet. 
  530.    4.  Prompt the user to select a part and a rotation angle.
  531.    5.  Verify that the selected part lies in current ucs plane.
  532.    6.  Retrieve the mass property and obtain the centroid of the part.
  533.    7.  Duplicate a copy (Template) of the selected part
  534.           and rotate the Template about the centroid of the part.
  535.    8.  Obtain the bounding box of the Template.
  536.    9.  Copy and place the Template to the metal sheet, beginning
  537.           from left to right, from bottom to top until it fills
  538.           up the sheet.
  539.    10. Print out the area of the metal sheet and the part, the total
  540.           number of parts in the layout and the material utilization
  541.           rate corresponding to the layout.
  542. -*/
  543. /*************************************************************************/
  544.  
  545. static void
  546. /*FCN*/create_layout_func ()
  547. {
  548.     ap_Real  sheet_l, sheet_w, sheet_area, urate;
  549.     ap_Real  part_l, part_w, part_area, part_angle;
  550.     ap_Objid Sheet, Part, Template, Temp;
  551.     ap_Massprop     mp;
  552.     ap_Trans3d   m;
  553.     ads_name chosen1, chosen2;
  554.     ads_point  loc, smin, smax, tmin, tmax, pc, pd;
  555.     ads_point  pt, rot_axis[2];
  556.     int      stat, i, j, ncolumn, nrow, ntotal;
  557.  
  558.     /* Initialize API */
  559.  
  560.     stat = ap_init();
  561.     if (stat != AP_NORMAL)
  562.         goto Error0;
  563.  
  564.     /* Prompt the user to select a rectangular region for metal sheet */
  565.  
  566.     stat = select_region(/*MSG22*/"\nSelect a rectangular sheet:", &Sheet, chosen1, loc);
  567.     if(stat == FALSE)
  568.         goto Error0;
  569.  
  570.     /* Highlight the selected entity */
  571.  
  572.     ads_redraw(chosen1, 3);
  573.  
  574.     /* Verify region in current ucs plane */
  575.  
  576.     stat = verify_region_in_ucs(Sheet);
  577.     if(stat == FALSE) {
  578.         ads_printf(/*MSG23*/"\nThe selected region must lie in current ucs plane.");
  579.         goto Error2;
  580.     }
  581.  
  582.     /* Verify that the selected region is a rectangular sheet,
  583.            and retrieve its border, size and area. */
  584.  
  585.     stat = verify_region_rectangular(Sheet, smin, smax);
  586.     if(stat == FALSE)
  587.         goto Error1;
  588.  
  589.     sheet_l = fabs(smax[X] - smin[X]);
  590.     sheet_w = fabs(smax[Y] - smin[Y]);
  591.     sheet_area = sheet_l * sheet_w;
  592.  
  593.     /* Prompt the user to select a part pattern which will
  594.            be blanked out from the sheet */
  595.  
  596.     stat = select_region(/*MSG24*/"\nSelect a part:", &Part, chosen2, loc);
  597.     if(stat == FALSE)
  598.         goto Error1;
  599.  
  600.     /* Highlight the selected entity */
  601.  
  602.     ads_redraw(chosen2, 3);
  603.  
  604.     /* Verify that the selected region is in xy plane */
  605.  
  606.     stat = verify_region_in_ucs(Part);
  607.     if(stat == FALSE) {
  608.         ads_printf
  609.         (/*MSG25*/"\nThe selected entity must lie in current ucs plane.");
  610.         goto Error2;
  611.     }
  612.  
  613.     /* Prompt the user to enter rotation angle for the 
  614.            selected part */
  615.  
  616.     part_angle = 0.0;
  617.     stat = ads_getreal (/*MSG26*/"\n\nRotation angle of part <0.0>: ", &part_angle);
  618.     if (stat == RTCAN)
  619.         goto Error2;
  620.  
  621.     /* Retrieve the mass properties of the part and
  622.            obtain the centroid pc of the selected part */
  623.  
  624.     stat = ap_get_massprop(Part, &mp);
  625.     if(stat != AP_NORMAL) {
  626.         ads_printf(/*MSG27*/"\nUnable to retrieve mass properties.");
  627.         goto Error2;
  628.     }
  629.  
  630.     pc[X] = mp.centroid.x;
  631.     pc[Y] = mp.centroid.y;
  632.     pc[Z] = mp.centroid.z;
  633.     part_area = mp.area;
  634.  
  635.     /* Duplicate a copy of the part called Template and rotate
  636.            Template about the center of the its bounding box */
  637.  
  638.     stat = ap_dup_obj(Part, &Template);
  639.     if (stat != AP_NORMAL)
  640.         goto Error2;
  641.  
  642.     /* Define a rotation axis from pc to pd which is 
  643.        perpendicular to ucs plane */
  644.  
  645.     pd[X] = pc[X];
  646.     pd[Y] = pc[Y];
  647.     pd[Z] = 1.0;
  648.  
  649.     trans_uc2wc(pc, FALSE, rot_axis[0]);
  650.     trans_uc2wc(pd, FALSE, rot_axis[1]);
  651.  
  652.     /* Rotate Template about the rotation axis through 
  653.        the specified angle part_angle */
  654.  
  655.     part_angle = part_angle * PI / 180.0;
  656.     stat = ap_rotate_axis(rot_axis, part_angle, m);
  657.     if (stat != AP_NORMAL)
  658.         goto Error2;
  659.     stat = ap_move_obj(Template, m, FALSE);
  660.     if (stat != AP_NORMAL)
  661.         goto Error2;
  662.  
  663.     /* Retrieve the bounding box for the Template */
  664.  
  665.     stat = ap_obj2extents(Template, TRUE, tmin, tmax);
  666.     if (stat != AP_NORMAL)
  667.         goto Error2;
  668.     part_l = fabs(tmax[X] - tmin[X]);
  669.     part_w = fabs(tmax[Y] - tmin[Y]);
  670.  
  671.     /* Verify that the validity of the size for the Template */
  672.  
  673.     if((part_l < EPSILON) || (part_w < EPSILON)) {
  674.         ads_printf(/*MSG28*/"\nThe selected part is too narrow.");
  675.         ap_del_obj(Template);
  676.         goto Error2;
  677.     }
  678.  
  679.     /* Compute the number of columns and rows that can fit
  680.            into the sheet without overlaping each other */
  681.  
  682.     ncolumn = sheet_l / part_l;
  683.     nrow = sheet_w / part_w;
  684.     ntotal = ncolumn * nrow;
  685.     if(ntotal > 1000) {
  686.         ads_printf(/*MSG29*/"\nCan't lay out more than 1000 copies.");
  687.         goto Error2;
  688.     }
  689.  
  690.     /* Move Template to the low-left corner of the sheet
  691.            which is the beginning position of the layout */
  692.  
  693.     pt[X] = smin[X] - tmin[X];
  694.     pt[Y] = smin[Y] - tmin[Y];
  695.     pt[Z] = 0.0;
  696.     trans_uc2wc(pt, TRUE, pd);
  697.     stat = ap_translate(pd[X], pd[Y], pd[Z], m);
  698.     if (stat != AP_NORMAL)
  699.         goto Error2;
  700.     stat = ap_move_obj(Template, m, FALSE);
  701.     if (stat != AP_NORMAL)
  702.         goto Error2;
  703.  
  704.     /* The layout process begins from the left to the right,
  705.        from the bottom to the top until it fills up the whole sheet */
  706.  
  707.     for (j=0; j<nrow; j++) {
  708.         for (i=0; i<ncolumn; i++) {
  709.             stat = ap_dup_obj(Template, &Temp);
  710.             if (stat != AP_NORMAL)
  711.                 goto Error2;
  712.             pt[X] = i * part_l;
  713.             pt[Y] = j * part_w;
  714.             pt[Z] = 0.0;
  715.             trans_uc2wc(pt, TRUE, pd);
  716.             stat = ap_translate(pd[X], pd[Y], pd[Z], m);
  717.             if (stat != AP_NORMAL)
  718.                 goto Error2;
  719.             stat = ap_move_obj(Temp, m, FALSE);
  720.             if (stat != AP_NORMAL)
  721.                 goto Error2;
  722.             stat = ap_post_obj(Temp, AP_POSTWIRE);
  723.             if (stat != AP_NORMAL)
  724.                 goto Error2;
  725.         }
  726.     }
  727.  
  728.     /* Calculate the material utilization percentage */
  729.  
  730.     urate = 100.0 * ntotal * part_area / sheet_area;
  731.  
  732.     /* Print out the results */
  733.  
  734.     ads_printf(/*MSG30*/"\nMetal sheet area = %f", sheet_area);
  735.     ads_printf(/*MSG31*/"\nPart area = %f", part_area);
  736.     ads_printf(/*MSG32*/"\nTotal number of parts = %d", ntotal);
  737.     if((urate > -1000.0) && (urate < 1000.0))
  738.         ads_printf(/*MSG33*/"\nMaterial utilization = %8.3f %c", urate, '%');
  739.     else
  740.         ads_printf(/*MSG34*/"\nMaterial utilization is out of the range.");
  741.  
  742.     stat = ap_del_obj(Template);
  743.     if (stat != AP_NORMAL)
  744.         goto Error2;
  745.  
  746. Error2:
  747.     ads_redraw(chosen2, 4);
  748.  
  749. Error1:
  750.     ads_redraw(chosen1, 4);
  751.  
  752. Error0:
  753.     ads_retvoid();
  754.     return;
  755. }
  756.  
  757. /*************************************************************************/
  758. /* .doc select_region() */
  759. /*+
  760.    This routine prompts the user to select a region 
  761. -*/
  762. /*************************************************************************/
  763.  
  764. static ap_Bool
  765. /*FCN*/select_region (prompt, sol, ename, loc)
  766.   char  *prompt;
  767.   ap_Objid  *sol;
  768.   ads_name   ename;
  769.   ads_point  loc;
  770. {
  771.     int  stat;
  772.     ap_Objtype  otype;
  773.  
  774.     stat = ads_entsel(prompt, ename, loc);
  775.     if(stat != RTNORM)
  776.         return FALSE;
  777.  
  778.     /* Verify that the selected entity is an AME object */
  779.  
  780.     stat = ap_name2obj(ename, sol);
  781.     if(stat != AP_NORMAL) {
  782.         ads_printf(/*MSG35*/"\nThe selected entity is not a region.");
  783.         return FALSE;
  784.     }
  785.  
  786.     /* Verify that the AME object is a region */
  787.  
  788.     stat = ap_get_objtype(*sol, &otype);
  789.     if((stat != AP_NORMAL) || (otype != AP_REGION)) {
  790.         ads_printf(/*MSG36*/"\nThe selected entity is not a region.");
  791.         return FALSE;
  792.     }
  793.     return TRUE;
  794. }
  795.  
  796. /*************************************************************************/
  797. /* .doc define_gear_pline() */
  798. /*+
  799.    This routine computes the gear profile based on the input 
  800.    arguments gear_d (pitch diameter), number_t (number of teeth)
  801.    and alpha (pressure angle). It returns a polyline vertex array pts
  802.    and the total number of vertices npoint contained in the polyline.
  803.    The routine first generates an involute tooth, then rotates and
  804.    copies the tooth to obtain a complete gear profile. The gear profile
  805.    is defined in the xy plane of wcs and centered at the origin.
  806. -*/
  807. /*************************************************************************/
  808.  
  809. static ap_Bool
  810. /*FCN*/define_gear_pline (gear_d, number_t, alpha, pts, npoint)
  811.   ap_Real  gear_d, alpha;
  812.   ap_Swp_pts  pts[];
  813.   int      number_t, *npoint;
  814. {
  815.     ap_Real  angle_a, angle_b, angle_c, angle_d, angle_e, angle_f;
  816.     ap_Real  angle_h, angle_i, angle_j, angle_k;
  817.     ap_Real  angle_rot, cos_rot, sin_rot, omega, phi, temp;
  818.     ap_Real  rad_pitch, rad_base, rad_adden, rad_deden;
  819.     int  i, j, k, nt;
  820.  
  821.     if((gear_d <= 0.0) || (number_t <= 2) || (number_t > 50))
  822.         return FALSE;
  823.  
  824.     nt = 10 * number_t + 1;
  825.     phi = alpha * PI / 180;
  826.  
  827.     /* Define radius for pitch circle */
  828.  
  829.     rad_pitch = gear_d / 2;
  830.  
  831.     /* Define radius for base circle */
  832.  
  833.     rad_base = rad_pitch * cos (phi);
  834.  
  835.     /* Define radius for addendum circle */
  836.  
  837.     rad_adden = rad_pitch + gear_d / number_t;
  838.  
  839.     /* Define radius for dedendum circle */
  840.  
  841.     rad_deden = rad_pitch - 1.25 * gear_d / number_t;
  842.  
  843.     if (rad_deden > rad_base)
  844.         rad_deden = 0.99 * rad_base;
  845.     temp = rad_adden * rad_adden / (rad_base * rad_base) - 1;
  846.     omega = sqrt (temp);
  847.  
  848.     /* Define some key angles corresponding to tooth profile */
  849.  
  850.     angle_i = PI/ (2 * number_t);
  851.     angle_j = angle_i + tan (phi) - phi;
  852.     angle_k = angle_j;
  853.     angle_h = angle_j - omega + atan (omega);
  854.     angle_a = angle_j - 2 * PI / number_t;
  855.     angle_b = (angle_a - angle_j) / 2;
  856.     angle_c = - angle_k;
  857.     angle_d = - angle_j;
  858.     angle_e = - angle_i;
  859.     angle_f = - angle_h;
  860.  
  861.     /* Define the coordinates of the polyline vertices 
  862.            for one tooth profile that consists  of line
  863.            and arc segments */
  864.  
  865.     pts[0].x = rad_deden * cos (angle_a);
  866.     pts[0].y = rad_deden * sin (angle_a);
  867.     pts[0].type = AP_PT_LINE;
  868.  
  869.     pts[1].x = rad_deden * cos (angle_b);
  870.     pts[1].y = rad_deden * sin (angle_b);
  871.     pts[1].type = AP_PT_LINE;
  872.  
  873.     pts[2].x = rad_deden * cos (angle_c);
  874.     pts[2].y = rad_deden * sin (angle_c);
  875.     pts[2].type = AP_PT_ARCEND;
  876.  
  877.     pts[3].x = rad_base * cos (angle_d);
  878.     pts[3].y = rad_base * sin (angle_d);
  879.     pts[3].type = AP_PT_LINE;
  880.  
  881.     pts[4].x = rad_pitch * cos (angle_e);
  882.     pts[4].y = rad_pitch * sin (angle_e);
  883.     pts[4].type = AP_PT_LINE;
  884.  
  885.     pts[5].x = rad_adden * cos (angle_f);
  886.     pts[5].y = rad_adden * sin (angle_f);
  887.     pts[5].type = AP_PT_ARCEND;
  888.  
  889.     pts[6].x = rad_adden;
  890.     pts[6].y = 0.0;
  891.     pts[6].type = AP_PT_LINE;
  892.  
  893.     pts[7].x = pts[5].x;
  894.     pts[7].y = -pts[5].y;
  895.     pts[7].type = AP_PT_ARCEND;
  896.  
  897.     pts[8].x = pts[4].x;
  898.     pts[8].y = -pts[4].y;
  899.     pts[8].type = AP_PT_LINE;
  900.  
  901.     pts[9].x = pts[3].x;
  902.     pts[9].y = -pts[3].y;
  903.     pts[9].type = AP_PT_ARCEND;
  904.  
  905.     pts[10].x = pts[2].x;
  906.     pts[10].y = -pts[2].y;
  907.     pts[10].type = AP_PT_LINE;
  908.  
  909.     /* Rotate and copy one tooth profile to obtain
  910.            a complete gear profile */
  911.  
  912.     for (i=1; i<number_t; i++) {
  913.         angle_rot = i * 2 * PI / number_t;
  914.         cos_rot = cos (angle_rot);
  915.         sin_rot = sin (angle_rot);
  916.  
  917.         for (j=1; j<11; j++) {
  918.             k = 10 * i + j;
  919.             pts[k].x = cos_rot * pts[j].x - sin_rot * pts[j].y;
  920.             pts[k].y = sin_rot * pts[j].x + cos_rot * pts[j].y;
  921.             pts[k].type = pts[j].type;
  922.         }
  923.     }
  924.  
  925.     pts[nt-1].x = pts[0].x;
  926.     pts[nt-1].y = pts[0].y;
  927.     pts[nt-1].type = pts[0].type;
  928.  
  929.     *npoint = nt;
  930.     return TRUE;
  931. }
  932.  
  933. /*************************************************************************/
  934. /* .doc define_rectangle_pline() */
  935. /*+
  936.    This routine computes the rectangle profile based on the input 
  937.    arguments length and width. It returns a polyline vertex array pts
  938.    and the total number of vertices npoint contained in the polyline.
  939.    The rectangle is defined in the xy plane of ucs with lts low-left
  940.    corner at the origin.
  941. -*/
  942. /*************************************************************************/
  943.  
  944. static ap_Bool
  945. /*FCN*/define_rectangle_pline (length, width, pts, npoint)
  946.   ap_Real  length, width;
  947.   ap_Swp_pts  pts[];
  948.   int      *npoint;
  949. {
  950.  
  951.     if((length <= 0.0) || (width <= 0.0))
  952.         return FALSE;
  953.     pts[0].x = 0.0;
  954.     pts[0].y = 0.0;
  955.     pts[0].type = AP_PT_LINE;
  956.  
  957.     pts[1].x = length;
  958.     pts[1].y = 0.0;
  959.     pts[1].type = AP_PT_LINE;
  960.  
  961.     pts[2].x = length;
  962.     pts[2].y = width;
  963.     pts[2].type = AP_PT_LINE;
  964.  
  965.     pts[3].x = 0.0;
  966.     pts[3].y = width;
  967.     pts[3].type = AP_PT_LINE;
  968.  
  969.     pts[4].x = 0.0;
  970.     pts[4].y = 0.0;
  971.     pts[4].type = AP_PT_LINE;
  972.  
  973.     *npoint = 5;
  974.     return TRUE;
  975. }
  976.  
  977. /*************************************************************************/
  978. /* .doc trans_wc2uc() */
  979. /*+
  980.    Transform a point p in wcs into point q in ucs
  981.    If vec = TRUE, then p is a vector
  982.    If vec = FALSE, then p is a point
  983. -*/
  984. /*************************************************************************/
  985.  
  986. static void
  987. /*FCN*/trans_wc2uc(p,vec,q)
  988.   ads_point p, q;
  989.   ap_Bool vec;
  990. {
  991.     struct resbuf rbfrom, rbto;
  992.  
  993.     rbfrom.restype = RTSHORT;
  994.     rbto.restype = RTSHORT;
  995.     rbfrom.resval.rint = 0;           /* from world */
  996.     rbto.resval.rint = 1;             /* to ucs */
  997.     ads_trans(p, &rbfrom, &rbto, vec, q);
  998. }
  999.  
  1000. /*************************************************************************/
  1001. /* .doc trans_uc2wc() */
  1002. /*+
  1003.    Transform a point p in ucs into point q in wcs
  1004.    If vec = TRUE, then p is a vector
  1005.    If vec = FALSE, then p is a point
  1006. -*/
  1007. /*************************************************************************/
  1008.  
  1009. static void
  1010. /* FCN */trans_uc2wc(p,vec,q)
  1011.   ads_point p, q;
  1012.   ap_Bool vec;
  1013. {
  1014.     struct resbuf rbfrom, rbto;
  1015.  
  1016.     rbfrom.restype = RTSHORT;
  1017.     rbto.restype = RTSHORT;
  1018.     rbfrom.resval.rint = 1;           /* from ucs */
  1019.     rbto.resval.rint = 0;             /* to world */
  1020.     ads_trans(p, &rbfrom, &rbto, vec, q);
  1021. }
  1022.  
  1023. /*************************************************************************/
  1024. /* .doc get_region_plane() */
  1025. /*+
  1026.    This routine obtains the co-planar matrix of the given region. 
  1027. -*/
  1028. /*************************************************************************/
  1029.  
  1030. static ap_Bool
  1031. /*FCN*/get_region_plane(obj, mat)
  1032.   ap_Objid   obj;
  1033.   ap_Trans3d  mat;
  1034. {
  1035.     ap_Objinfo   oinfo;
  1036.     ap_Objid  object;
  1037.     int stat;
  1038.  
  1039.     /* Retrieve object information and verify that it is a region */
  1040.  
  1041.     stat = ap_get_objinfo(obj, &oinfo);
  1042.     if((stat != AP_NORMAL) || (oinfo.obj != AP_REGION)) {
  1043.         ads_printf(/*MSG37*/"\nThe selected entity is not a region.");
  1044.         return FALSE;
  1045.     }
  1046.     stat = ap_identity(mat);
  1047.     if(stat != AP_NORMAL)
  1048.         return FALSE;
  1049.     stat = ap_compose(oinfo.mat, mat, mat);
  1050.     if(stat != AP_NORMAL)
  1051.         return FALSE;
  1052.  
  1053.     /* Compose matrix through CSG tree's left child branch */
  1054.  
  1055.     while (oinfo.type == AP_BOO) {
  1056.         object = oinfo.prim.boo.op1;
  1057.         stat = ap_get_objinfo(object, &oinfo);
  1058.         if(stat != AP_NORMAL)
  1059.             return FALSE;
  1060.         stat = ap_compose(oinfo.mat, mat, mat);
  1061.         if(stat != AP_NORMAL)
  1062.             return FALSE;
  1063.     }
  1064.     return TRUE;
  1065. }
  1066.  
  1067. /*************************************************************************/
  1068. /* .doc verify_region_in_ucs() */
  1069. /*+
  1070.    This routine verifies that a given region
  1071.    lies in the xy plane of current ucs.
  1072. -*/
  1073. /*************************************************************************/
  1074.  
  1075. static ap_Bool
  1076. /*FCN*/verify_region_in_ucs(obj)
  1077.   ap_Objid   obj;
  1078. {
  1079.     ads_point   pc1, pc2, norm1, norm2;
  1080.     ap_Trans3d  mat;
  1081.     int   stat;
  1082.  
  1083.     /* Retrieve the co-planar matrix of the region */
  1084.  
  1085.     stat = get_region_plane(obj, mat);
  1086.     if(stat != TRUE) {
  1087.         ads_printf(/*MSG38*/"\nUnable to retrieve region's co-planar matrix.");
  1088.         return FALSE;
  1089.     }
  1090.  
  1091.     /* Retrieve a point that lies in the same plane as the region */
  1092.  
  1093.     pc1[X] = mat[0][3];
  1094.     pc1[Y] = mat[1][3];
  1095.     pc1[Z] = mat[2][3];
  1096.  
  1097.     /* Retrieve the normal to the region plane */
  1098.  
  1099.     norm1[X] = mat[0][2];
  1100.     norm1[Y] = mat[1][2];
  1101.     norm1[Z] = mat[2][2];
  1102.  
  1103.     /* Retrieve the current ucs matrix */
  1104.  
  1105.     stat = ap_get_ucsmat(mat);
  1106.     if (stat != AP_NORMAL)
  1107.         return FALSE;
  1108.  
  1109.     /* Retrieve the origin of current ucs */
  1110.  
  1111.     pc2[X] = mat[0][3];
  1112.     pc2[Y] = mat[1][3];
  1113.     pc2[Z] = mat[2][3];
  1114.  
  1115.     /* Retrieve the normal of current ucs plane */
  1116.  
  1117.     norm2[X] = mat[0][2];
  1118.     norm2[Y] = mat[1][2];
  1119.     norm2[Z] = mat[2][2];
  1120.  
  1121.     /* Verify that region plane and ucs plane are coincident */
  1122.  
  1123.     stat = verify_planes_equal(pc1, norm1, pc2, norm2);
  1124.     if (stat == TRUE)
  1125.         return TRUE;
  1126.     else
  1127.         return FALSE;
  1128. }
  1129.  
  1130. /*************************************************************************/
  1131. /* .doc verify_planes_equal() */
  1132. /*+
  1133.    This routine verify whether two planes are coincident.
  1134.    The plane is defined by its normal and a through point.
  1135. -*/
  1136. /*************************************************************************/
  1137. static ap_Bool
  1138. /*FCN*/verify_planes_equal (org1, norm1, org2, norm2)
  1139.   ads_point  org1, norm1, org2, norm2;
  1140. {
  1141.     ads_point  dir;
  1142.     ads_real   dx, dy, dz, du, dv;
  1143.  
  1144.     if (((fabs (norm1[X]) < EPSILON) &&
  1145.          (fabs (norm1[Y]) < EPSILON) &&
  1146.          (fabs (norm1[Z]) < EPSILON)) ||
  1147.         ((fabs (norm2[X]) < EPSILON) &&
  1148.          (fabs (norm2[Y]) < EPSILON) &&
  1149.          (fabs (norm2[Z]) < EPSILON)))
  1150.         return FALSE;
  1151.  
  1152.     dx = norm1[Y]*norm2[Z] - norm1[Z]*norm2[Y];
  1153.     dy = norm1[Z]*norm2[X] - norm1[X]*norm2[Z];
  1154.     dz = norm1[X]*norm2[Y] - norm1[Y]*norm2[X];
  1155.  
  1156.     dir[X] = org2[X] - org1[X];
  1157.     dir[Y] = org2[Y] - org1[Y];
  1158.     dir[Z] = org2[Z] - org1[Z];
  1159.     du = dir[X]*norm1[X] + dir[Y]*norm1[Y] + dir[Z]*norm1[Z];
  1160.     dv = dir[X]*norm2[X] + dir[Y]*norm2[Y] + dir[Z]*norm2[Z];
  1161.  
  1162.     if ((fabs (dx) < EPSILON) && (fabs (dy) < EPSILON) &&
  1163.         (fabs (dz) < EPSILON) && (fabs (du) < EPSILON) &&
  1164.         (fabs (dv) < EPSILON))
  1165.         return TRUE;
  1166.     else
  1167.         return FALSE;
  1168. }
  1169.  
  1170. /*************************************************************************/
  1171. /* .doc verify_region_rectangular() */
  1172. /*+
  1173.    This routine verify that a selected region is a rectangle
  1174.    which satisfies the following criteria:
  1175.  
  1176.    1.  It contains no holes (flaws) in it.
  1177.    2.  It consists of four line edges and four vertices.
  1178.    3.  All the edges are either horizontal or vertical.
  1179.  
  1180.    If all the criteria are satisfied, it returns TRUE as well as 
  1181.    the low_left and top_right corners of the rectangle in ucs.
  1182. -*/
  1183. /*************************************************************************/
  1184.  
  1185. static ap_Bool
  1186. /*FCN*/verify_region_rectangular(obj, pmin, pmax)
  1187.   ap_Objid   obj;
  1188.   ads_point   pmin, pmax;
  1189. {
  1190.     ap_Featid    *llist;
  1191.     ap_Edgelist  *elist, *seg;
  1192.     ads_point   pt1, pt2;
  1193.     ads_real    xa[PMAX], ya[PMAX];
  1194.     int   nloop, nedge, nvertex, index, stat, stat1, stat2, find_curve;
  1195.  
  1196.     /* Retrieve all the loops contained in the region */
  1197.  
  1198.     stat = ap_obj2loops(obj, &llist);
  1199.     if (stat != AP_NORMAL)
  1200.         goto Error1;
  1201.  
  1202.     nloop = 0;
  1203.     while (llist[nloop] != (ap_Featid)NULL)
  1204.         nloop++;
  1205.  
  1206.     /* Verify that there are no inside loops (holes) 
  1207.            contained in the region */
  1208.  
  1209.     if(nloop != 1) {
  1210.         ads_printf(/*MSG39*/"\nThe selected sheet may have holes in it");
  1211.         goto Error1;
  1212.     }
  1213.  
  1214.     /* Retrieve all the edges contained in the loop */
  1215.  
  1216.     stat = ap_loop2edges(obj, llist[0], TRUE, &elist);
  1217.     if (stat != AP_NORMAL) {
  1218.         ads_printf (/*MSG40*/"\nUnable to retrieve edges from loop.");
  1219.         goto Error2;
  1220.     }
  1221.  
  1222.     /* Count the total number of edges contained in the loop
  1223.            and check whether there are any curve edges */
  1224.  
  1225.     nedge = 0;
  1226.     find_curve = FALSE;
  1227.     seg = elist;
  1228.     while (seg != NULL) {
  1229.         if (seg->edge->ctype != AP_LINE)
  1230.             find_curve = TRUE;
  1231.  
  1232.         seg = seg->edgenext;
  1233.         nedge++;
  1234.     }
  1235.  
  1236.     /* Verify that the region consists of 4 edges */
  1237.  
  1238.     if(nedge != 4) {
  1239.         ads_printf(/*MSG41*/"\nThe selected sheet has %d edges. ", nedge);
  1240.         ads_printf(/*MSG42*/"It is not a rectangle.");
  1241.         goto Error2;
  1242.     }
  1243.  
  1244.     /* Verify that all the edges are line segments */
  1245.  
  1246.     if(find_curve == TRUE) {
  1247.         ads_printf(/*MSG43*/"\nThe selected sheet contains curve edges. ");
  1248.         ads_printf(/*MSG44*/"It is not a rectangle.");
  1249.         goto Error2;
  1250.     }
  1251.  
  1252.     /* Verify that all the edges are either horizontal or vertical */
  1253.  
  1254.     seg = elist;
  1255.     while (seg != NULL) {
  1256.  
  1257.         trans_wc2uc(seg->edge->s_pt, FALSE, pt1);
  1258.         trans_wc2uc(seg->edge->e_pt, FALSE, pt2);
  1259.         stat1 = verify_line_horizontal(pt1, pt2);
  1260.         stat2 = verify_line_vertical(pt1, pt2);
  1261.         if((stat1 == FALSE) && (stat2 == FALSE)) {
  1262.             ads_printf(/*MSG45*/"\nThe selected region is not horizontal.");
  1263.             goto Error2;
  1264.         }
  1265.         seg = seg->edgenext;
  1266.     }
  1267.  
  1268.     /* Retrieve all the vertices contained in the region */
  1269.  
  1270.     nvertex = 0;
  1271.     seg = elist;
  1272.     while (seg != NULL) {
  1273.         trans_wc2uc(seg->edge->s_pt, FALSE, pt1);
  1274.         stat = insert_pt_to_array(pt1, xa, ya, nvertex);
  1275.         if (stat == TRUE)
  1276.             nvertex = nvertex + 1;
  1277.         trans_wc2uc(seg->edge->e_pt, FALSE, pt2);
  1278.         stat = insert_pt_to_array(pt2, xa, ya, nvertex);
  1279.         if (stat == TRUE)
  1280.             nvertex = nvertex + 1;
  1281.         seg = seg->edgenext;
  1282.     }
  1283.  
  1284.     /* Verify that the region contains only 4 vertices */
  1285.  
  1286.     if(nvertex != 4) {
  1287.         ads_printf(/*MSG46*/"\nThe selected sheet has %d vertex. ",nvertex);
  1288.         ads_printf(/*MSG47*/"It is not a rectangle.");
  1289.         goto Error2;
  1290.     }
  1291.  
  1292.     /* Find the bounding box of the rectangle.
  1293.        Pmin is the low-left corner,
  1294.        Pmax is the top-right corner of the rectangle */
  1295.  
  1296.     pmin[X] = find_minimum(xa, nvertex, &index);
  1297.     pmin[Y] = find_minimum(ya, nvertex, &index);
  1298.     pmin[Z] = 0.0;
  1299.     pmax[X] = find_maximum(xa, nvertex, &index);
  1300.     pmax[Y] = find_maximum(ya, nvertex, &index);
  1301.     pmax[Z] = 0.0;
  1302.  
  1303.     free(llist);
  1304.     ap_free_edgelist(elist);
  1305.     ads_retvoid();
  1306.     return TRUE;
  1307.  
  1308. Error2:
  1309.     ap_free_edgelist(elist);
  1310.  
  1311. Error1:
  1312.     free(llist);
  1313.     ads_retvoid();
  1314.     return FALSE;
  1315.  
  1316. }
  1317.  
  1318. /*************************************************************************/
  1319. /* .doc verify_line_horizontal() */
  1320. /*+
  1321.    This routine verify that a line defined by points pt1 & pt2 
  1322.    is a horizontal line in ucs. The endpoints of the line must
  1323.    not be coincident. pt1 and pt2 are in ucs coordinates.
  1324. -*/
  1325. /*************************************************************************/
  1326.  
  1327. static ap_Bool
  1328. /*FCN*/verify_line_horizontal(pt1, pt2)
  1329.   ads_point  pt1, pt2;
  1330. {
  1331.     ads_real  dy;
  1332.     int  stat;
  1333.  
  1334.     stat = verify_2pts_equal (pt1, pt2);
  1335.     if(stat == TRUE)
  1336.         return FALSE;
  1337.  
  1338.     dy = pt2[Y] - pt1[Y];
  1339.     if(fabs(dy) < EPSILON)
  1340.         return TRUE;
  1341.     else
  1342.         return FALSE;
  1343. }
  1344.  
  1345. /*************************************************************************/
  1346. /* .doc verify_line_vertical() */
  1347. /*+
  1348.    This routine verify that a line defined by points pt1 & pt2 
  1349.    is a vertical line in ucs. The endpoints of the line must
  1350.    not be coincident. pt1 and pt2 are in ucs coordinates.
  1351. -*/
  1352. /*************************************************************************/
  1353.  
  1354. static ap_Bool
  1355. /*FCN*/verify_line_vertical(pt1, pt2)
  1356.   ads_point  pt1, pt2;
  1357. {
  1358.     ads_real  dx;
  1359.     int  stat;
  1360.  
  1361.     stat = verify_2pts_equal (pt1, pt2);
  1362.     if(stat == TRUE)
  1363.         return FALSE;
  1364.  
  1365.     dx = pt2[X] - pt1[X];
  1366.     if(fabs(dx) < EPSILON)
  1367.         return TRUE;
  1368.     else
  1369.         return FALSE;
  1370. }
  1371.  
  1372. /*************************************************************************/
  1373. /* .doc insert_pt_to_array() */
  1374. /*+
  1375.    This routine insert the x-coordinate and y-coordinate of
  1376.    a given point pt into arrays xa[] and ya[] respectively.
  1377.    Coincident points are merged into one point only.
  1378. -*/
  1379. /*************************************************************************/
  1380.  
  1381. static ap_Bool
  1382. /* FCN */insert_pt_to_array (pt, xa, ya, np)
  1383.   ads_point  pt;
  1384.   ads_real  xa[], ya[];
  1385.   int  np;
  1386. {
  1387.     int  i;
  1388.  
  1389.     if(np <= 0) {
  1390.         xa[0] = pt[X];
  1391.         ya[0] = pt[Y];
  1392.         return TRUE;
  1393.     }
  1394.  
  1395.     for(i = 0; i < np; i++) {
  1396.         if ((fabs(pt[X] - xa[i]) < EPSILON) &&
  1397.             (fabs(pt[Y] - ya[i]) < EPSILON))
  1398.             return FALSE;
  1399.     }
  1400.  
  1401.     xa[np] = pt[X];
  1402.     ya[np] = pt[Y];
  1403.     return TRUE;
  1404. }
  1405.  
  1406. /*************************************************************************/
  1407. /* .doc verify_2pts_equal() */
  1408. /*+
  1409.    Verify whether two points p1 & p2 are coincident or not.
  1410. -*/
  1411. /*************************************************************************/
  1412.  
  1413. static ap_Bool
  1414. /* FCN */verify_2pts_equal (p1, p2)
  1415.   ads_point  p1, p2;
  1416. {
  1417.     ads_real   dx, dy, dz;
  1418.  
  1419.     dx = fabs (p2[X] - p1[X]);
  1420.     dy = fabs (p2[Y] - p1[Y]);
  1421.     dz = fabs (p2[Z] - p1[Z]);
  1422.  
  1423.     if ((dx < EPSILON) && (dy < EPSILON) && (dz < EPSILON))
  1424.         return TRUE;
  1425.     else
  1426.         return FALSE;
  1427. }
  1428.  
  1429. /*************************************************************************/
  1430. /* .doc find_maximum() */
  1431. /*+
  1432.    Find the maximum value among nt elements contained in array[].
  1433.    Return the maximum and the index associated with the maximum.
  1434. -*/
  1435. /*************************************************************************/
  1436. static ads_real
  1437. /*FCN*/find_maximum (array, nt, index)
  1438.   ads_real  array[];
  1439.   int       nt, *index;
  1440. {
  1441.     ads_real  maximum;
  1442.     int  i;
  1443.  
  1444.     maximum = array[0];
  1445.     *index = 0;
  1446.     for (i=0; i<nt; i++)
  1447.     {
  1448.         if (array[i] > maximum)
  1449.         {
  1450.             maximum = array[i];
  1451.             *index = i;
  1452.         }
  1453.     }
  1454.     return (maximum);
  1455. }
  1456.  
  1457. /*************************************************************************/
  1458. /* .doc find_minimum() */
  1459. /*+
  1460.    Find the minimum value among nt elements contained in array[].
  1461.    Return the minimum and the index associated with the minimum.
  1462. -*/
  1463. /*************************************************************************/
  1464. static ads_real
  1465. /*FCN*/find_minimum (array, nt, index)
  1466.   ads_real  array[];
  1467.   int       nt, *index;
  1468. {
  1469.     ads_real  minimum;
  1470.     int  i;
  1471.  
  1472.     minimum = array[0];
  1473.     *index = 0;
  1474.     for (i=0; i<nt; i++)
  1475.     {
  1476.         if (array[i] < minimum)
  1477.         {
  1478.             minimum = array[i];
  1479.             *index = i;
  1480.         }
  1481.     }
  1482.     return (minimum);
  1483. }
  1484.  
  1485.  
  1486. /* EOF */
  1487.