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

  1. /* Next available MSG number is 40 */
  2.  
  3. /* SYMMETRY.C
  4.  
  5.   Copyright (C) 1992 by Autodesk, Inc.
  6. ----------------------------------------------------------------------------
  7.     
  8.      Permission to use, copy, modify, and distribute this software
  9.      for any purpose and without fee is hereby granted, provided
  10.      that the above copyright notice appears in all copies and that
  11.      both that copyright notice and this permission notice appear in
  12.      all supporting documentation.
  13.   
  14.      THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
  15.      WARRANTY.  ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR
  16.      PURPOSE AND OF MERCHANTABILITY ARE HEREBY DISCLAIMED.
  17.  
  18. ----------------------------------------------------------------------------
  19.  
  20. DESCRIPTION:
  21.  
  22. A sample API application.
  23.  
  24. symmetry.c finds out if a region is circularly (radially) symmetric and/or 
  25. symmetric with respect to its X-axis and/or Y-axis. X-axis and Y-axis are
  26. I and J components of the principal directions respectively. For circularly
  27. symmetric objects, the output is a "repetition factor".
  28.  
  29.  
  30.         Command: symmetry
  31.         Select a region: Pick the region
  32.         Enter precision (1 to 8) <3>: 1
  33.  
  34. "Precision" adjusts the level of calculations (similar to SOLSUBDIV
  35. variable used in mass property calculations). If the object has relatively
  36. small features, it is better to use a higher precision.
  37.  
  38.         Circular/X/Y/ <All>: x
  39.  
  40. To check if the object is circularly symmetric, you select "Circular"
  41. option, and so on. The default option "All" lists all the symmetry
  42. information of the object.
  43.  
  44. For "Circular" symmetry, you need to enter an upper limit for
  45. the calculations:
  46.  
  47.         Enter upper limit for circular symmetry (3 to 360) <20>: 90
  48.  
  49. A repetition factor is searched between 3 and this upper limit.
  50. If the object has a repetition factor above this upper limit,
  51. it can not be found, and the object gets classified as "not circularly
  52. symmetric".
  53.  
  54. A sample output is as follows:
  55.  
  56.         Region is circularly symmetric. Repetition factor is 5.
  57.         Region is symmetric about X-axis (red).
  58.         Region is not symmetric about Y-axis (blue).
  59.  
  60. The X direction of the principal axis is shown in red, Y direction in
  61. blue.
  62.  
  63.  
  64. THEORY:
  65.  
  66. Steps to find if a region has symmetry or not are as follows:
  67.  
  68. 1) The region is tranformed so that its centroid coincides with the
  69. origin of WCS, I component of its principal directions lines up with
  70. the X axis of WCS, and J component of its principal directions lines
  71. up with the Y axis of WCS. These transformations are
  72. performed on a duplicate region, which is deleted at the end.
  73.  
  74. 2) Rays are fired radially from origin and with "theta" degrees apart. 
  75. The number of rays is determined by the "precision", i.e. 
  76. # of rays = p * 12. Theta is 360 / (# of rays). A master array is formed
  77. from the edge classifications of these rays wrt the region.
  78.  
  79. 3) The region is considered to be symmetric about X axis if a ray above 
  80. X axis has the same classification as its counterpart below X axis. If the
  81. ray has been fired by an angle "alpha" its counterpart is the ray that's
  82. been fired by "360 - alpha" or "-alpha".
  83.  
  84. 4) The region is considered to be symmetric about Y axis if a ray on the left 
  85. of Y axis has the same classification as its counterpart on the right of Y axis.
  86. If the angle of the ray is "beta", its counterpart is the ray with angle
  87. "180 - beta".
  88.  
  89. 5) To check if the region has a circular symmetry of factor n, an 
  90. angle, "gamma = 360 / n" is defined. Then each ray in the master array is 
  91. compared to the ray "gamma" degrees away (which gets classified), 
  92. i.e. ray at "alpha" is compared to ray at "alpha + gamma". If all
  93. the rays pass the comparison test, then the region is considered to be 
  94. circularly symmetric with a repetition factor of n. A range of numbers
  95. between 3 and "the upper limit" are input for n.
  96.  
  97. */
  98.  
  99. /***************************************************************************/
  100. /*  INCLUDES  */
  101. /***************************************************************************/
  102.  
  103. #include <stdio.h>
  104. #include <time.h>
  105. #include <math.h>
  106. #include <string.h>
  107. #include "adslib.h"
  108. #include "aplib.h"
  109.  
  110. /***************************************************************************/
  111. /*  DEFINES  */
  112. /***************************************************************************/
  113.  
  114. #define DEFAULT_PRECISION       3
  115. #define DEFAULT_LIMIT           20
  116. #define PI                      3.14159265358927
  117. #define EPS                     1.0e-5
  118. #define EQUAL                   1
  119. #define NOT_EQUAL               0
  120. #define TRUE                    1
  121. #define FALSE                   0
  122. #define NELEM(a)                (sizeof a  / sizeof a[0])
  123.  
  124. /*************************************************************************/
  125. /* FUNCTION DECLARATIONS */
  126. /*************************************************************************/
  127.  
  128. void    find_sym();
  129. ap_Bool funcload();
  130. ap_Bool adjust();
  131. ap_Bool get_wcs_align();
  132. ap_Bool look_for_sym();
  133. ap_Bool create_list();
  134. ap_Bool get_ray_length();
  135. int     circular();
  136. int     x_axis();
  137. int     y_axis();
  138. int     not_equal();
  139. ap_Bool draw_axis();
  140. void    trans_pt();
  141. void    set_ucs();
  142. void    set_wcs();
  143. void    command_echo_off();
  144. void    command_echo_on();
  145.  
  146. struct resbuf  echo1, echo2;
  147. ap_Real ray_length;
  148.  
  149. struct ads_comm
  150. {
  151.         char *cstring;
  152.         void (*cfunc) ();
  153. };
  154.  
  155. struct ads_comm asolid_comm[]  =
  156. {
  157.         {/*MSG1*/"C:SYMMETRY",  find_sym},
  158. };
  159.  
  160. /*************************************************************************/
  161. /* .doc main() */
  162. /*+
  163. -*/
  164. /*************************************************************************/
  165.  
  166. void
  167. /*FCN*/main(argc,  argv)
  168.   int argc;
  169.   char **argv;
  170. {
  171.     int stat;
  172.     int scode  =  RSRSLT;
  173.  
  174.     ads_init(argc,  argv);
  175.     for (;;)
  176.     {
  177.         if ((stat  =  ads_link(scode))  <  0)
  178.         {
  179.             ads_printf(/*MSG2*/"TEST: bad status from ads_link()  =  %d\n",  stat);
  180.             fflush(stdout);
  181.             exit(1);
  182.         }
  183.         scode  =  RSRSLT;             /* default return code */
  184.  
  185.         switch (stat)
  186.         {
  187.         case RQXLOAD:                 /* Load & register functions */
  188.             scode  =  funcload() ? RSRSLT : RSERR;
  189.             break;
  190.  
  191.         case RQXUNLD:                 /* Unloading */
  192.             break;
  193.  
  194.         case RQSUBR:                  /* Evaluate external lisp function */
  195.             if ((stat  =  ads_getfuncode())  <  0)
  196.             {
  197.                 ads_printf(/*MSG3*/"\nUnrecognized  command.\n");
  198.                 ads_retvoid();
  199.                 break;
  200.             }
  201.             if (asolid_comm[stat].cfunc  !=  (void(*)())NULL)
  202.             {
  203.                 (*asolid_comm[stat].cfunc)();
  204.                 ads_retvoid();
  205.             }
  206.             break;
  207.  
  208.         default:
  209.             break;
  210.         }
  211.     }
  212. }
  213.  
  214.  
  215. /*************************************************************************/
  216. /* .doc funcload() */
  217. /*+
  218.    Load external functions into AutoCAD system
  219. -*/
  220. /*************************************************************************/
  221.  
  222. static ap_Bool
  223. /*FCN*/funcload()
  224. {
  225.     int i;
  226.  
  227.     for (i  =  0; i  <  NELEM( asolid_comm ); i++)
  228.     {
  229.         if (ads_defun(asolid_comm[i].cstring,  i)  !=  RTNORM)
  230.         {
  231.             ads_printf(/*MSG4*/"Unable to register %s command.\n",
  232.                        asolid_comm[i].cstring);
  233.             return FALSE;
  234.         }
  235.     }
  236.  
  237.     return TRUE;
  238. }
  239.  
  240. /*************************************************************************/
  241. /* .doc find_sym() */
  242. /*+
  243.     Find symmetry
  244. -*/
  245. /*************************************************************************/
  246.  
  247. void
  248. /*FCN*/find_sym()
  249. {
  250.     ads_name name;
  251.     ap_Objid obj, region;
  252.     ads_point pt;
  253.     int flag, stat, p, csym = 0, xsym = 0, ysym = 0, asym = 0, limit;
  254.     char op[20];
  255.     ap_Objtype type;
  256.  
  257.     if(ap_init() != AP_NORMAL)
  258.         return;
  259.     command_echo_off();
  260.     set_wcs();
  261.  
  262. /* Prompt user to select the region */
  263.  
  264.     if(ads_entsel(/*MSG5*/"Select a region: ", name, pt) != RTNORM){
  265.         ads_printf(/*MSG6*/"Selection failed.\n");
  266.         goto Error1;
  267.     }
  268.     ads_printf("\n");
  269.  
  270. /* Check if the entity is an object */
  271.  
  272.     if(ap_name2obj(name, &obj) != AP_NORMAL){
  273.         ads_printf(/*MSG7*/"Selected entity is not an object.\n");
  274.         goto Error1;
  275.     }
  276.  
  277. /* Check if the object is a region */
  278.  
  279.     if(ap_get_objtype(obj, &type) != AP_NORMAL){
  280.         ads_printf(/*MSG8*/"API error: can not get the type of the object.\n");
  281.         goto Error1;
  282.     }
  283.     if(type == AP_SOLID){
  284.         ads_printf(/*MSG9*/"Selected entity is not a region.\n");
  285.         goto Error1;
  286.     }
  287.  
  288. /* Prompt user for input parameters */
  289.  
  290.     p = DEFAULT_PRECISION;
  291.     do{
  292.         flag = FALSE;
  293.         ads_initget(2 + 4, NULL);
  294.         if ((stat = ads_getint(/*MSG10*/"Enter precision (1 to 8) <3>: ", &p)) == RTNORM){
  295.             if(p > 8){
  296.                 ads_printf(/*MSG11*/"Precision should be less than 8.\n");
  297.                 flag = TRUE;
  298.             }
  299.         }
  300.         if(stat == RTCAN)
  301.             goto Error1;
  302.     }while(flag);
  303.  
  304.     do{
  305.         flag = FALSE;
  306.         ads_initget(0, /*MSG12*/"Circular C X Y All A");
  307.         strcpy(op, "");
  308.         if (ads_getkword(/*MSG13*/"Circular/X/Y/ <All>: ", op) < 0)
  309.             goto Error1;
  310.         if (strlen(op) == 0)
  311.             strcpy(op, /*MSG14*/"All");
  312.  
  313.         if(!strcmp(op, /*MSG15*/"Circular") || !strcmp(op, /*MSG16*/"C"))
  314.             csym = 1;
  315.         else if(!strcmp(op, /*MSG17*/"X"))
  316.             xsym = 2;
  317.         else if(!strcmp(op, /*MSG18*/"Y"))
  318.             ysym = 3;
  319.         else if(!strcmp(op, /*MSG19*/"All") || !strcmp(op, /*MSG20*/"A"))
  320.             asym = 4;
  321.         else{
  322.             ads_printf(/*MSG21*/"Invalid operation. Please try again.\n");
  323.             flag = TRUE;
  324.         }
  325.     }while(flag);
  326.  
  327.     if(csym || asym){
  328.         limit = DEFAULT_LIMIT;
  329.         do{
  330.             flag = FALSE;
  331.             ads_initget(2 + 4, NULL);
  332.             if ((stat = ads_getint
  333.                  (/*MSG22*/"Enter upper limit for circular symmetry (3 to 360) <20>: ", &limit))
  334.                 == RTNORM){
  335.                 if(limit > 360 || limit < 3){
  336.                     ads_printf(/*MSG23*/"Upper limit should be between 3 and 360.\n");
  337.                     flag = TRUE;
  338.                 }
  339.             }
  340.             if(stat == RTCAN)
  341.                 goto Error1;
  342.         }while(flag);
  343.     }
  344.  
  345. /* Position the region for symmetry calculations */
  346.  
  347.     if(adjust(obj, ®ion) != TRUE)
  348.         goto Error;
  349.  
  350. /* Find if the region is symmetric or not */
  351.  
  352.     if(look_for_sym(region, csym + xsym + ysym + asym, p, limit) != TRUE)
  353.         goto Error;
  354.  
  355. /* Delete the duplicate region */
  356.  
  357.     ap_del_obj(region);
  358.  
  359. Error1:
  360.     set_ucs();
  361.     command_echo_on();
  362.     ads_retvoid();
  363.     return;
  364.  
  365. Error:
  366.     ap_del_obj(region);
  367.     set_ucs();
  368.     command_echo_on();
  369.     ads_printf(/*MSG24*/"API error is encountered.\n");
  370.     ads_retvoid();
  371.     return;
  372. }
  373.  
  374. /*************************************************************************/
  375. /* .doc adjust() */
  376. /*+
  377.  This function duplicates the region, and positions it so that its centroid 
  378.  is at the origin of WCS and the principal directions are lined up with X
  379.  and Y axis.
  380. -*/
  381. /*************************************************************************/
  382.  
  383. ap_Bool
  384. /*FCN*/adjust(obj, region)
  385.   ap_Objid obj, *region;
  386. {
  387.     ap_Objid dup_region;
  388.     ap_Trans3d forward, mat, al_wcs, trans;
  389.     ap_Massprop mp;
  390.     ap_Real angle;
  391.  
  392. /* Duplicate the region */
  393.  
  394.     if(ap_dup_obj(obj, &dup_region) != AP_NORMAL)
  395.         return FALSE;
  396.     *region = dup_region;
  397.  
  398. /* Get the matrix necessary to align region with XY plane of WCS */
  399.  
  400.     if(get_wcs_align(*region, forward, al_wcs) != TRUE)
  401.         return FALSE;
  402.  
  403. /* Align the region */
  404.  
  405.     if(ap_move_obj(*region, al_wcs, 1) != AP_NORMAL)
  406.         return FALSE;
  407.  
  408. /* Draw pricipal axis */
  409.  
  410.     if(draw_axis(*region, forward) != TRUE)
  411.         return FALSE;
  412.  
  413. /* Position the region so that its centroid coincides with the origin */
  414.  
  415.     if(ap_get_massprop(*region, &mp)!= AP_NORMAL)
  416.         return FALSE;
  417.     if(ap_translate(-mp.centroid.x, -mp.centroid.y, -mp.centroid.z, trans)!= AP_NORMAL)
  418.         return FALSE;
  419.     if(ap_move_obj(*region, trans, 0)!= AP_NORMAL)
  420.         return FALSE;
  421.  
  422. /* Rotate the region so that principal dir. line up with X and Y axes */
  423.  
  424.     angle = acos(mp.prindir[0][0]);
  425.     if(mp.prindir[0][1] > 0)
  426.         angle = -angle;
  427.     if(ap_rotate_z(angle, mat)!= AP_NORMAL)
  428.         return FALSE;
  429.     if(ap_move_obj(*region, mat, 0)!= AP_NORMAL)
  430.         return FALSE;
  431.  
  432.     return TRUE;
  433. }
  434.  
  435. /*************************************************************************/
  436. /* .doc look_for_sym() */
  437. /*+
  438.   Calls symmetry functions according to user input 
  439. -*/
  440. /*************************************************************************/
  441.  
  442. ap_Bool
  443. /*FCN*/look_for_sym(region, sym, p, limit)
  444.   ap_Objid region;
  445.   int sym, p, limit;
  446. {
  447.     register i;
  448.     int no, factor;
  449.     ap_Seglist *slist[100];
  450.  
  451.     no = p * 12;
  452.     ads_printf(/*MSG25*/"Looking for symmetry...\n");
  453.  
  454. /* Create the classification array */
  455.  
  456.     if(create_list(region, slist, no) != TRUE)
  457.         return FALSE;
  458.  
  459. /* Circular Symmetry */
  460.  
  461.     if(sym == 1 || sym == 4){
  462.         factor = circular(region, slist, no, limit);
  463.         if(!factor)
  464.             return FALSE;
  465.         else if(factor > 0)
  466.             ads_printf(/*MSG26*/"Region is circularly symmetric. Repetition factor is %d.\n", factor);
  467.         else ads_printf(/*MSG27*/"Region is not circularly symmetric.\n");
  468.     }
  469.  
  470. /* X-axis Symmetry */
  471.  
  472.     if(sym == 2 || sym == 4){
  473.         if(x_axis(slist, no))
  474.             ads_printf(/*MSG28*/"Region is symmetric about X-axis (red).\n");
  475.         else ads_printf(/*MSG29*/"Region is not symmetric about X-axis (red).\n");
  476.     }
  477.  
  478. /* Y-axis Symmetry */
  479.  
  480.     if(sym == 3 || sym == 4){
  481.         if(y_axis(slist, no))
  482.             ads_printf(/*MSG30*/"Region is symmetric about Y-axis (blue).\n");
  483.         else ads_printf(/*MSG31*/"Region is not symmetric about Y-axis (blue).\n");
  484.     }
  485.  
  486. /* Free the classification list */
  487.  
  488.     for(i = no - 1; i >= 0; i--)
  489.         free(slist[i]);
  490.  
  491.     return TRUE;
  492. }
  493.  
  494. /*************************************************************************/
  495. /* .doc create_list() */
  496. /*+
  497.    This function throws rays radially, classifies them, and stores the
  498.    classifications in a list.
  499. -*/
  500. /*************************************************************************/
  501.  
  502. ap_Bool
  503. /*FCN*/create_list(region, slist, no)
  504.   ap_Objid region;
  505.   ap_Seglist *slist[];
  506.   int no;
  507. {
  508.     register j;
  509.     ap_Edgeinfo einfo;
  510.     ap_Real theta = 0.0, tplus;
  511.  
  512.     if(get_ray_length(region) != TRUE)
  513.         return FALSE;
  514.  
  515. /* Define the edge to be classified */
  516.  
  517.     einfo.ctype = AP_LINE;
  518.     einfo.edge_len = ray_length;
  519.     einfo.s_parm = 0.0;
  520.     einfo.e_parm = ray_length;
  521.     einfo.s_pt[0] = einfo.s_pt[1] = einfo.s_pt[2] = 0.0;
  522.     einfo.e_pt[2] = 0.0;
  523.  
  524. /* Rotate and classify the edge wrt to the region */
  525.  
  526.     tplus = 2 * PI / no;
  527.     for(j = 0; j < no; j++){
  528.         if(ap_rotate_z(theta, einfo.edge_rm) != AP_NORMAL)
  529.             return FALSE;
  530.         einfo.e_pt[0] = ray_length * einfo.edge_rm[0][0];
  531.         einfo.e_pt[1] = ray_length * einfo.edge_rm[0][1];
  532.         if(ap_class_edge(region, &einfo, &slist[j]) != AP_NORMAL)
  533.             return FALSE;
  534.         theta += tplus;
  535.     }
  536.  
  537.     return TRUE;
  538. }
  539.  
  540. /*************************************************************************/
  541. /* .doc circular() */
  542. /*+
  543.    Looks for circular symmetry
  544. -*/
  545. /*************************************************************************/
  546.  
  547. int
  548. /*FCN*/circular(region, slist, no, limit)
  549.   ap_Objid region;
  550.   ap_Seglist *slist[];
  551.   int no, limit;
  552. {
  553.     int flag, factor = -1;
  554.     register j, k;
  555.     ap_Edgeinfo einfo;
  556.     ap_Real div, theta, theta2, tplus;
  557.     ap_Seglist *list2;
  558.  
  559. /* Define the edge to be classified */
  560.  
  561.     einfo.ctype = AP_LINE;
  562.     einfo.edge_len = ray_length;
  563.     einfo.s_parm = 0.0;
  564.     einfo.e_parm = ray_length;
  565.     einfo.s_pt[0] = einfo.s_pt[1] = einfo.s_pt[2] = 0.0;
  566.     einfo.e_pt[2] = 0.0;
  567.     tplus = 2 * PI / no;
  568.  
  569. /* For every possible factor less than or equal to limit */
  570.  
  571.     for(k = limit; k > 2; k--){
  572.         div = 6.283185307 / k;
  573.         flag = EQUAL;
  574.         theta = 0.0;
  575.         for(j = 0; j < no; j++){
  576.  
  577. /* Rotate and classify the edge wrt to the region */
  578.  
  579.             theta2 = theta + div;
  580.             if(ap_rotate_z(theta2, einfo.edge_rm) != AP_NORMAL)
  581.                 return FALSE;
  582.             einfo.e_pt[0] = ray_length * einfo.edge_rm[0][0];
  583.             einfo.e_pt[1] = ray_length * einfo.edge_rm[0][1];
  584.             if(ap_class_edge(region, &einfo, &list2) != AP_NORMAL)
  585.                 return FALSE;
  586.  
  587. /* Compare the classification to the one in the classification list */
  588.  
  589.             if(not_equal(slist[j], list2)){
  590.                 flag = NOT_EQUAL;
  591.                 break;
  592.             }
  593.             ap_free_seglist(list2);
  594.             theta += tplus;
  595.         }
  596.         if(flag) {
  597.             factor = k;
  598.             break;
  599.         }
  600.     }
  601.     return factor;
  602. }
  603.  
  604. /*************************************************************************/
  605. /* .doc x_axis() */
  606. /*+
  607.    Looks for symmetry about X axis
  608. -*/
  609. /*************************************************************************/
  610.  
  611. int
  612. /*FCN*/x_axis(slist, no)
  613.   ap_Seglist *slist[];
  614. {
  615.     register j, k;
  616.     int flag = TRUE;
  617.  
  618. /* Compare the classifications on both sides of the X axis */
  619.  
  620.     for(j = 1, k = no - 1; j != k; j++, k--)
  621.         if(not_equal(slist[j], slist[k])){
  622.             flag = FALSE;
  623.             break;
  624.         }
  625.  
  626.     return flag;
  627. }
  628.  
  629. /*************************************************************************/
  630. /* .doc y_axis() */
  631. /*+ 
  632.    Looks for symmetry about Y axis
  633. -*/
  634. /*************************************************************************/
  635.  
  636. int
  637. /*FCN*/y_axis(slist, no)
  638.   ap_Seglist *slist[];
  639. {
  640.     register j, k;
  641.     int flag = TRUE;
  642.  
  643. /* Compare the classifications on both sides of the Y axis */
  644.  
  645.     for(j = no / 4 + 1, k = no / 4 - 1; j != k; j++, k--){
  646.         if(k < 0) k = no - 1;
  647.         if(not_equal(slist[j], slist[k])){
  648.             flag = FALSE;
  649.             break;
  650.         }
  651.     }
  652.  
  653.     return flag;
  654. }
  655.  
  656. /*************************************************************************/
  657. /* .doc not_equal() */
  658. /*+ 
  659.    Compares two segments returned from edge classification
  660. -*/
  661. /*************************************************************************/
  662.  
  663. int
  664. /*FCN*/not_equal(seg1, seg2)
  665.   ap_Seglist *seg1, *seg2;
  666. {
  667.     ap_Real t1a, t2a, t1b, t2b;
  668.     ap_Class class1, class2;
  669.  
  670.  
  671.     for(;;){
  672.         if(!seg1 && !seg2)
  673.             return FALSE;
  674.         if((seg1 && !seg2) || (!seg1 && seg2))
  675.             return TRUE;
  676.         t1a = seg1->seg.s_parm;
  677.         t1b = seg1->seg.e_parm;
  678.         class1 = seg1->seg.edge_class;
  679.         t2a = seg2->seg.s_parm;
  680.         t2b = seg2->seg.e_parm;
  681.         class2 = seg2->seg.edge_class;
  682.         if(class1 != class2 || fabs(t1a - t2a) > EPS || fabs(t1b - t2b) > EPS)
  683.             return TRUE;
  684.         seg1 = seg1->segnext;
  685.         seg2 = seg2->segnext;
  686.     }
  687. }
  688.  
  689. /*************************************************************************/
  690. /* .doc draw_axis() */
  691. /*+
  692.    Gets the principal directions and draws them at the centroid
  693.    of the region.
  694. -*/
  695. /*************************************************************************/
  696.  
  697. ap_Bool
  698. /*FCN*/draw_axis(region, forward)
  699.   ap_Objid region;
  700.   ap_Trans3d forward;
  701. {
  702.  
  703.     ap_Massprop mp;
  704.     ads_point c, p0, p1;
  705.     ap_Trans3d backward;
  706.     struct resbuf  rb;
  707.     ap_Real vsize, scale;
  708.  
  709.  
  710. /* Get its principal directions */
  711.  
  712.     if(ap_get_massprop(region, &mp) != AP_NORMAL)
  713.         return FALSE;
  714.     c[0] = mp.centroid.x;
  715.     c[1] = mp.centroid.y;
  716.     c[2] = mp.centroid.z;
  717.  
  718. /* Scale lines wrt current viewsize */
  719.  
  720.     ads_getvar(/*MSG0*/"VIEWSIZE", &rb);
  721.     vsize = rb.resval.rreal;
  722.     scale = 0.2 * vsize;
  723.  
  724.     p0[0] = mp.prindir[0][0] * scale + c[0];
  725.     p0[1] = mp.prindir[0][1] * scale + c[1];
  726.     p0[2] = mp.prindir[0][2] * scale + c[2];
  727.     p1[0] = mp.prindir[1][0] * scale + c[0];
  728.     p1[1] = mp.prindir[1][1] * scale + c[1];
  729.     p1[2] = mp.prindir[1][2] * scale + c[2];
  730.  
  731. /* Transform the vectors onto the original region */
  732.  
  733.     if(ap_invert(forward, backward) != AP_NORMAL)
  734.         return FALSE;
  735.     trans_pt(p0, backward);
  736.     trans_pt(p1, backward);
  737.     trans_pt(c, backward);
  738.  
  739. /* Draw X direction in red */
  740.  
  741.     ads_grdraw(c, p0, 1, 0);
  742.  
  743.  
  744. /* Draw Y direction in blue */
  745.  
  746.     ads_grdraw(c, p1, 5, 0);
  747.  
  748.     return TRUE;
  749. }
  750.  
  751. /*************************************************************************/
  752. /* .doc trans_pt() */
  753. /*+
  754.    Tranforms a given point by a given matrix
  755. -*/
  756. /*************************************************************************/
  757.  
  758. void
  759. /*FCN*/trans_pt(pt, m)
  760.   ads_point pt;
  761.   ap_Trans3d m;
  762. {
  763.     ap_Real x, y, z;
  764.  
  765.     x = pt[0]; y = pt[1]; z = pt[2];
  766.  
  767.     pt[0] = x * m[0][0] + y * m[0][1] + z * m[0][2] +  m[0][3];
  768.     pt[1] = x * m[1][0] + y * m[1][1] + z * m[1][2] +  m[1][3];
  769.     pt[2] = x * m[2][0] + y * m[2][1] + z * m[2][2] +  m[2][3];
  770. }
  771.  
  772. /*************************************************************************/
  773. /* .doc set_ucs() */
  774. /*+
  775.    Reset current ucs by "prev" option of UCS command
  776. -*/
  777. /*************************************************************************/
  778.  
  779. void
  780. /*FCN*/set_ucs()
  781. {
  782.     ads_command(RTSTR, /*MSG32*/"_.ucs", RTSTR, /*MSG33*/"_prev", NULL);
  783.     ads_command (RTSTR, /*MSG34*/"_.UCSICON", RTSTR, /*MSG35*/"_ON", NULL);
  784. }
  785.  
  786. /*************************************************************************/
  787. /* .doc set_wcs() */
  788. /*+
  789.    Set wcs by "WCS" option of UCS command
  790. -*/
  791. /*************************************************************************/
  792.  
  793. void
  794. /*FCN*/set_wcs()
  795. {
  796.     ads_command (RTSTR, /*MSG36*/"_.UCSICON", RTSTR, /*MSG37*/"_OFF", NULL);
  797.     ads_command(RTSTR, /*MSG38*/"_.ucs", RTSTR, /*MSG39*/"_world", NULL);
  798. }
  799.  
  800. /*************************************************************************/
  801. /* .doc command_echo_off() */
  802. /*+
  803.    Suppress command echo.
  804. -*/
  805. /*************************************************************************/
  806.  
  807. static void
  808. /*FCN*/command_echo_off()
  809. {
  810.     ads_getvar (/*MSG0*/"CMDECHO", &echo1);
  811.     echo2.restype = RTSHORT;
  812.     echo2.resval.rint = FALSE;
  813.     ads_setvar (/*MSG0*/"CMDECHO", &echo2);
  814. }
  815.  
  816. /*************************************************************************/
  817. /* .doc command_echo_on() */
  818. /*+
  819.    Resume command echo.
  820. -*/
  821. /*************************************************************************/
  822.  
  823. static void
  824. /*FCN*/command_echo_on()
  825. {
  826.     ads_setvar (/*MSG0*/"CMDECHO", &echo1);
  827. }
  828.  
  829. /*************************************************************************/
  830. /* .doc get_wcs_align() */
  831. /*+
  832.    Aligns the region with the XY plane of WCS.
  833. -*/
  834. /*************************************************************************/
  835.  
  836. ap_Bool
  837. /*FCN*/get_wcs_align(region, forward, al_wcs)
  838.   ap_Objid region;
  839.   ap_Trans3d forward, al_wcs;
  840. {
  841.     ap_Edgeinfo *einfo;
  842.     ap_Featid eid = 1;
  843.     ap_Objinfo info;
  844.  
  845. /* Get any edge rigid motion matrix . This matrix defines the plane */
  846. /*   the region is on.                                              */
  847.  
  848.     if(ap_get_edgeinfo(region, eid, &einfo) != AP_NORMAL)
  849.         return FALSE;
  850.     if(ap_invert(einfo->edge_rm, forward) != AP_NORMAL)
  851.         return FALSE;
  852.  
  853. /* Form the destination matrix */
  854.  
  855.     if(ap_get_objinfo(region, &info) != AP_NORMAL)
  856.         return FALSE;
  857.     if(ap_compose(forward, info.mat, al_wcs) != AP_NORMAL)
  858.         return FALSE;
  859.  
  860.     return TRUE;
  861. }
  862.  
  863. /*************************************************************************/
  864. /* .doc get_ray_length() */
  865. /*+
  866.    Calculates the extents of the region and assigns a suitable ray length
  867.    for classification.
  868. -*/
  869. /*************************************************************************/
  870.  
  871. ap_Bool
  872. /*FCN*/get_ray_length(region)
  873.   ap_Objid region;
  874. {
  875.     ads_point min, max;
  876.  
  877.     if(ap_obj2extents(region, FALSE, min, max) != AP_NORMAL)
  878.         return FALSE;
  879.     ray_length = ads_distance(min, max);
  880.  
  881.     return TRUE;
  882. }
  883.  
  884. /*EOF*/
  885.