home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 13 / 13.iso / p / p037 / cr12_15.ddi / ADS1.LIB / UTIL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-12  |  45.0 KB  |  1,635 lines

  1. /*****************************************************************************
  2.       UTIL.C
  3.       ¬⌐┼v (C) 1988-1992  Autodesk ñ╜Ñq
  4.  
  5.       Ñ╗╡{ªíñwÑ╤ Autodesk ñ╜Ñq╡∙ÑU¬⌐┼v, ╢╚⌐≤ñU¡z▒í¬pñUÑi▒┬╗P▒zíu│\ÑiívíC
  6.       ╗╒ñUñú▒oÑHÑ⌠ª≤º╬ªí╡oªµ⌐╬ÑX¬⌐ª╣╡{ªí¬║íu¡∞⌐l╜Xív; ª²ñ╣│\▒zªb»S⌐w¡lÑ═
  7.       ¬║ñuº@ñW╡▓ªXª╣╡{ªí¬║íuÑ╪¬║╜Xív¿╧Ñ╬íCª│├÷│o├■¡lÑ═ñuº@¬║▒°Ñ≤ªpñU:
  8.  
  9.       ( i)  │]¡pñW╗Pñuº@ñW¼╥»┬║Θ░w╣∩ Autodesk ñ╜Ñq¬║▓ú½~íC
  10.       (ii)  ╕ⁿª│íu¬⌐┼v  (C) 1988-1992  Autodesk ñ╜Ñqív¬║¬⌐┼v│qºiíC
  11.  
  12.  
  13.  
  14.       AUTODESKñ╜Ñq┤ú¿╤ª╣╡{ªí╢╚¿╤º@íu├■ªⁿív¬║░╤ª╥, ª╙ÑBñú▒╞░úª│Ñ⌠ª≤┐∙╗~¬║
  15.       Ñi»αíCAUTODESKñ╜Ñq»Sª╣º_╗{Ñ⌠ª≤»S⌐wÑ╬│~ñº╛A║┘⌐╩, ÑHñ╬░╙╖~╛P░Γ⌐╥┴⌠ºt
  16.       ÑX¿π¬║½O├╥íCAUTODESKñ╜ÑqªP«╔ÑτñúÑX¿πª╣╡{ªí░⌡ªµ«╔ñ@⌐wñú╖|íuññ┬_ív⌐╬
  17.       íuº╣Ñ■╡L╗~ív¬║½O├╥íC
  18.  
  19.  
  20.   Description: Library of various utility functions. This is not a well
  21.                organized library, just a rather random collection of
  22.                functions. But you might find some of the functions useful.
  23.  
  24. *****************************************************************************/
  25.  
  26.  
  27. /****************************************************************************/
  28. /*  INCLUDES                                                                */
  29. /****************************************************************************/
  30.  
  31. #include <stdio.h>
  32. #include <math.h>
  33. #include <string.h>
  34. #include "adslib.h"
  35. #include "util.h"
  36.  
  37.  
  38. /****************************************************************************/
  39. /*  DEFINES                                                                 */
  40. /****************************************************************************/
  41.  
  42. #define ARBBOUND    0.015625          /* Bound for arbitrary matrix alg. */
  43. #define ZERO_BULGE  1e-7              /* Bulge which is considered zero  */
  44.  
  45.  
  46. /****************************************************************************/
  47. /*  STATIC VARIABLES                                                        */
  48. /****************************************************************************/
  49.  
  50. /* Save area for various AutoCAD system variables */
  51.  
  52. static struct resbuf cmdecho, blipmode, highlight, ucsicon, aunits, lunits,
  53.                      orthomode, osmode, snapmode, thickness, elevation,
  54.                      angdir;
  55.  
  56. static struct resbuf cmde, sortents;
  57.  
  58.  
  59. /****************************************************************************/
  60. /*  STATIC FUNCTIONS                                                        */
  61. /****************************************************************************/
  62.  
  63. static void sa_make_pickbox_equal_to_aperture _((int do_it));
  64. static int  sa_e2u _((ads_point p1, ads_name ent_name, int tested,
  65.                       ads_point m[4], ads_point normal, ads_point p2));
  66.  
  67.  
  68. /****************************************************************************/
  69. /*.doc sa_save_acad_vars(external) */
  70. /*+
  71.   Saves AutoCAD system variables which may negatively influence the
  72.   ads_command() function.
  73. -*/
  74. /****************************************************************************/
  75.  
  76.  
  77. void
  78. /*FCN*/sa_save_acad_vars()
  79. {
  80.     struct resbuf rb;
  81.  
  82.     ads_getvar("CMDECHO",   &cmdecho  );
  83.     ads_getvar("BLIPMODE",  &blipmode );
  84.     ads_getvar("HIGHLIGHT", &highlight);
  85.     ads_getvar("UCSICON",   &ucsicon  );
  86.     ads_getvar("AUNITS",    &aunits   );
  87.     ads_getvar("LUNITS",    &lunits   );
  88.     ads_getvar("ORTHOMODE", &orthomode);
  89.     ads_getvar("OSMODE",    &osmode   );
  90.     ads_getvar("SNAPMODE",  &snapmode );
  91.     ads_getvar("THICKNESS", &thickness);
  92.     ads_getvar("ELEVATION", &elevation);
  93.     ads_getvar("ANGDIR",    &angdir   );
  94.  
  95.     rb.rbnext      = NULL;
  96.     rb.restype     = RTSHORT;
  97.     rb.resval.rint = 0;
  98.  
  99.     ads_setvar("CMDECHO",  &rb);
  100.     ads_setvar("BLIPMODE", &rb);
  101.     ads_setvar("HIGHLIGHT",&rb);
  102.     ads_setvar("UCSICON",  &rb);
  103.     ads_setvar("AUNITS",   &rb);
  104.     ads_setvar("ORTHOMODE",&rb);
  105.     ads_setvar("OSMODE",   &rb);
  106.     ads_setvar("SNAPMODE", &rb);
  107.     ads_setvar("ANGDIR",   &rb);
  108.  
  109.     rb.resval.rint = 1;
  110.     ads_setvar("LUNITS",   &rb);
  111.  
  112.     rb.restype     = RTREAL;
  113.     rb.resval.rreal = 0.0;
  114.     ads_setvar("THICKNESS", &rb);
  115.     ads_setvar("ELEVATION", &rb);
  116. } /*sa_save_acad_vars*/
  117.  
  118.  
  119. /****************************************************************************/
  120. /*.doc sa_restore_acad_vars(external) */
  121. /*+
  122.   Restores the system variables which were saved by save_acad_vars().
  123. -*/
  124. /****************************************************************************/
  125.  
  126.  
  127. void
  128. /*FCN*/sa_restore_acad_vars()
  129. {
  130.     ads_setvar("BLIPMODE",  &blipmode );
  131.     ads_setvar("HIGHLIGHT", &highlight);
  132.     ads_setvar("UCSICON",   &ucsicon  );
  133.     ads_setvar("AUNITS",    &aunits   );
  134.     ads_setvar("LUNITS",    &lunits   );
  135.     ads_setvar("ORTHOMODE", &orthomode);
  136.     ads_setvar("OSMODE",    &osmode   );
  137.     ads_setvar("SNAPMODE",  &snapmode );
  138.     ads_setvar("CMDECHO",   &cmdecho  );
  139.     ads_setvar("THICKNESS", &thickness);
  140.     ads_setvar("ELEVATION", &elevation);
  141.     ads_setvar("ANGDIR",    &angdir   );
  142. } /*sa_restore_acad_vars*/
  143.  
  144.  
  145. /****************************************************************************/
  146. /*.doc sa_cmdecho_off(external) */
  147. /*+
  148.   Saves the value of the CMDECHO variable and sets it to 0.
  149. -*/
  150. /****************************************************************************/
  151.  
  152.  
  153. void
  154. /*FCN*/sa_cmdecho_off()
  155. {
  156.     struct resbuf rb;
  157.  
  158.     ads_getvar("CMDECHO", &cmde);
  159.  
  160.     rb.restype     = RTSHORT;
  161.     rb.resval.rint = 0;
  162.  
  163.     ads_setvar("CMDECHO", &rb);
  164. } /*sa_cmdecho_off*/
  165.  
  166.  
  167. /****************************************************************************/
  168. /*.doc sa_cmdecho_back(external) */
  169. /*+
  170.   Restores the original value of the CMDECHO variable.
  171. -*/
  172. /****************************************************************************/
  173.  
  174.  
  175. void
  176. /*FCN*/sa_cmdecho_back()
  177. {
  178.     ads_setvar("CMDECHO", &cmde);
  179. } /*sa_cmdecho_back*/
  180.  
  181.  
  182. /****************************************************************************/
  183. /*.doc sa_undo_group(external) */
  184. /*+
  185.   Begins an undo group.
  186. -*/
  187. /****************************************************************************/
  188.  
  189.  
  190. void
  191. /*FCN*/sa_undo_group()
  192. {
  193.     sa_cmdecho_off();
  194.     ads_command(RTSTR, /* NT */"_.UNDO", RTSTR, /* NT */"_GROUP", 0);
  195.     sa_cmdecho_back();
  196. } /*sa_undo_group*/
  197.  
  198.  
  199. /****************************************************************************/
  200. /*.doc sa_undo_end(external) */
  201. /*+
  202.   Ends the undo group.
  203. -*/
  204. /****************************************************************************/
  205.  
  206.  
  207. void
  208. /*FCN*/sa_undo_end()
  209. {
  210.     sa_cmdecho_off();
  211.     ads_command(RTSTR, /* NT */"_.UNDO", RTSTR, /* NT */"_END", 0);
  212.     sa_cmdecho_back();
  213. } /*sa_undo_end*/
  214.  
  215.  
  216. /****************************************************************************/
  217. /*.doc sa_set_sortents(external) */
  218. /*+
  219.   Sets the mode of picking. When entities overlap, the method of
  220.   disambiguating is controlled by the AutoCAD SORTENTS variable.
  221.   See the description for SORTENTS for full meaning of the pick modes.
  222. -*/
  223. /****************************************************************************/
  224.  
  225.  
  226. void
  227. /*FCN*/sa_set_sortents(pick_mode)
  228.   int pick_mode;
  229. {
  230.     struct resbuf rb_mode;
  231.  
  232.     rb_mode.rbnext = NULL;
  233.     rb_mode.restype = RTSHORT;
  234.     rb_mode.resval.rint = pick_mode;
  235.     ads_setvar("SORTENTS",&rb_mode);
  236. } /*sa_set_sortents*/
  237.  
  238.  
  239. /****************************************************************************/
  240. /*.doc sa_save_sortents(external) */
  241. /*+
  242.   Saves the value of the SORTENTS system variable. This function is
  243.   typically called if the value of SORTENTS is to be restored by calling
  244.   sa_restore_sortents() later.
  245.   NOTE: There is no stack of values maintain. Calling the function
  246.         overwrites the previous value in sortents.
  247. -*/
  248. /****************************************************************************/
  249.  
  250.  
  251. void
  252. /*FCN*/sa_save_sortents()
  253. {
  254.     ads_getvar("SORTENTS", &sortents);
  255. } /*sa_save_sortents*/
  256.  
  257.  
  258. /****************************************************************************/
  259. /*.doc sa_restore_sortents(external) */
  260. /*+
  261.   Restores the value of the AutoCAD variable SORTENTS to the value that
  262.   was obtained by a previous call to sa_save_sortents().
  263.   NOTE: This function must be called only if there was a previous call
  264.         to sa_save_sortents().
  265. -*/
  266. /****************************************************************************/
  267.  
  268.  
  269. void
  270. /*FCN*/sa_restore_sortents()
  271. {
  272.     ads_setvar("SORTENTS", &sortents);
  273. } /*sa_restore_sortents*/
  274.  
  275.  
  276. /****************************************************************************/
  277. /*.doc sa_make_pickbox_equal_to_aperture(external) */
  278. /*+
  279.   TRUE => Makes the value of PICKBOX variable equal to APERTURE variable.
  280.   FALSE=> Returns value of PICKBOX variable back.
  281. -*/
  282. /****************************************************************************/
  283.  
  284.  
  285. static void
  286. /*FCN*/sa_make_pickbox_equal_to_aperture(do_it)
  287.  
  288.   int do_it;
  289. {
  290.     static struct resbuf pickbox;
  291.     struct resbuf        aperture;
  292.  
  293.     if (do_it) {
  294.         ads_getvar("PICKBOX",  &pickbox );
  295.         ads_getvar("APERTURE", &aperture);
  296.         ads_setvar("PICKBOX",  &aperture);
  297.     } else { /*Return it back*/
  298.         ads_setvar("PICKBOX",  &pickbox );
  299.     }
  300. } /*sa_make_pickbox_equal_to_aperture*/
  301.  
  302.  
  303. /****************************************************************************/
  304. /*.doc sa_points_are_collinear(external) */
  305. /*+
  306.   Returns TRUE if the three given points are collinear.
  307. -*/
  308. /****************************************************************************/
  309.  
  310.  
  311. int
  312. /*FCN*/sa_points_are_collinear(p1, p2, p3)
  313.  
  314.   ads_point p1, p2, p3;
  315. {
  316.     ads_point v1, v2;
  317.     int       ok1, ok2;
  318.  
  319.     SUB_PNT(v1, p2, p1);
  320.     SUB_PNT(v2, p3, p1);
  321.  
  322.     ok1 = sa_normalize(v1);
  323.     ok2 = sa_normalize(v2);
  324.  
  325.     if (!ok1 || !ok2)
  326.         return(TRUE);
  327.  
  328.     return(fabs(DOTPROD(v1, v2)) > EPS_COS);
  329. } /*sa_points_are_collinear*/
  330.  
  331.  
  332. /****************************************************************************/
  333. /*.doc sa_cross(external) */
  334. /*+
  335.   Cross product of two vectors.
  336. -*/
  337. /****************************************************************************/
  338.  
  339.  
  340. void
  341. /*FCN*/sa_cross(v, v1, v2)
  342.  
  343.   ads_point v, v1, v2;
  344. {
  345.     v[X] = v1[Y] * v2[Z] - v1[Z] * v2[Y];
  346.     v[Y] = v1[Z] * v2[X] - v1[X] * v2[Z];
  347.     v[Z] = v1[X] * v2[Y] - v1[Y] * v2[X];
  348. } /*sa_cross*/
  349.  
  350.  
  351. /****************************************************************************/
  352. /*.doc sa_det(external) */
  353. /*+
  354.   Evaluates the determinant of 3x3 matrix. The given vectors a, b and c
  355.   are the rows of the matrix.
  356. -*/
  357. /****************************************************************************/
  358.  
  359.  
  360. double
  361. /*FCN*/sa_det(a, b, c)
  362.  
  363.   ads_point a, b, c;
  364. {
  365.     return(a[X] * (b[Y] * c[Z] - b[Z] * c[Y]) +
  366.            a[Y] * (b[Z] * c[X] - b[X] * c[Z]) +
  367.            a[Z] * (b[X] * c[Y] - b[Y] * c[X]));
  368. } /*sa_det*/
  369.  
  370.  
  371. /****************************************************************************/
  372. /*.doc sa_plane_from_point_and_normal(external) */
  373. /*+
  374.   Takes point on plane 'origin' and point on plane normal 'zaxis' and
  375.   returns two additional points 'xaxis' and 'yaxis' lying on the plane.
  376.   The points 'xaxis' and 'yaxis' are calculated based on the arbitrary axis
  377.   algorithm.
  378.  
  379.   Function returns one of the standard ADS result codes.
  380. -*/
  381. /****************************************************************************/
  382.  
  383.  
  384. int
  385. /*FCN*/sa_plane_from_point_and_normal(origin, zaxis, xaxis, yaxis)
  386.  
  387.   ads_point origin,zaxis;             /* Two input points      */
  388.   ads_point xaxis,yaxis;              /* Two calculated points */
  389. {
  390.     int       success;
  391.     ads_point normal;
  392.     ads_point m[3];
  393.  
  394.     SUB_PNT(normal, zaxis, origin);
  395.  
  396.     success = sa_make_arb_matrix(normal, m);
  397.     if (success != RTNORM)
  398.         return(RTERROR);
  399.  
  400.     ADD_PNT(xaxis, origin, m[X]);
  401.     ADD_PNT(yaxis, origin, m[Y]);
  402.  
  403.     return(RTNORM);
  404. } /*sa_plane_from_point_and_normal*/
  405.  
  406.  
  407. /****************************************************************************/
  408. /*.doc sa_3d_angle(external) */
  409. /*+
  410.   Returns the angle of triangle (apex,p1,p2). All  points are considered
  411.   threedimensional, the resulting angle is within interval <0;PI>.
  412. -*/
  413. /****************************************************************************/
  414.  
  415.  
  416. double
  417. /*FCN*/sa_3d_angle(apex, p1, p2)
  418.  
  419.   ads_point apex, p1, p2;
  420. {
  421.     ads_point v1, v2;
  422.     double    l1, l2;
  423.     double    cosa;
  424.     double    angle;
  425.  
  426.     SUB_PNT(v1, p1, apex); l1 = LENGTH(v1);
  427.     SUB_PNT(v2, p2, apex); l2 = LENGTH(v2);
  428.  
  429.     if ((l1 < EPS) || (l2 < EPS))
  430.         return(0.0);
  431.  
  432.     cosa = DOTPROD(v1, v2) / (l1 * l2);
  433.     if (cosa >  1.0)
  434.         cosa =  1.0;
  435.     if (cosa < -1.0)
  436.         cosa = -1.0;
  437.  
  438.     angle = acos(cosa);
  439.  
  440.     return(angle);
  441. } /*sa_3d_angle*/
  442.  
  443.  
  444. /****************************************************************************/
  445. /*.docsa_ rotate_point_around_axis(external) */
  446. /*+
  447.   Rotates point 'pp' around axis (p1,p2) through angle 'angle'. The axis
  448.   is oriented from 'p1' to 'p2'.
  449.  
  450.   Function returns one of the standard ADS result codes.
  451. -*/
  452. /****************************************************************************/
  453.  
  454.  
  455. int
  456. /*FCN*/sa_rotate_point_around_axis(pp, angle, p1, p2)
  457.  
  458.   ads_point pp;
  459.   double    angle;
  460.   ads_point p1, p2;
  461. {
  462.     ads_point p;
  463.     ads_point n;
  464.     double    cosa, sina, cosb, sinb, cosc, sinc;
  465.     double    lenxy,len;
  466.     double    px,pz;
  467.  
  468.     if (sa_points_are_collinear(pp, p1, p2))
  469.         return(RTREJ);
  470.  
  471.     SUB_PNT(n, p2, p1);
  472.  
  473.     lenxy = sqrt(SQR(n[X]) + SQR(n[Y]));
  474.  
  475.     if (lenxy > EPS) {
  476.         cosa = n[X] / lenxy;
  477.         sina = n[Y] / lenxy;
  478.     } else {
  479.         cosa = 1.0;
  480.         sina = 0.0;
  481.     }
  482.  
  483.     len  = LENGTH(n);
  484.     cosb = n[Z]  / len;
  485.     sinb = lenxy / len;
  486.  
  487.     cosc = cos(angle);
  488.     sinc = sin(angle);
  489.  
  490.     SUB_PNT(p, pp, p1);
  491.  
  492.     px   =  cosa * p[X] + sina * p[Y];
  493.     p[Y] = -sina * p[X] + cosa * p[Y];
  494.     p[X] =  px;
  495.  
  496.     pz   =  cosb * p[Z] + sinb * p[X];
  497.     p[X] = -sinb * p[Z] + cosb * p[X];
  498.     p[Z] =  pz;
  499.  
  500.     px   =  cosc * p[X] - sinc * p[Y];
  501.     p[Y] =  sinc * p[X] + cosc * p[Y];
  502.     p[X] =  px;
  503.  
  504.     pz   =  cosb * p[Z] - sinb * p[X];
  505.     p[X] =  sinb * p[Z] + cosb * p[X];
  506.     p[Z] =  pz;
  507.  
  508.     px   =  cosa * p[X] - sina * p[Y];
  509.     p[Y] =  sina * p[X] + cosa * p[Y];
  510.     p[X] =  px;
  511.  
  512.     ADD_PNT(pp, p, p1);
  513.  
  514.     return(RTNORM);
  515. } /*sa_rotate_point_around_axis*/
  516.  
  517.  
  518. /****************************************************************************/
  519. /*.doc sa_angle_around_axis(external) */
  520. /*+
  521.   Returns angle between points 'from' and 'to' measured around axis (p1,p2).
  522.   The axis is oriented from p1 to p2.
  523. -*/
  524. /****************************************************************************/
  525.  
  526.  
  527. double
  528. /*FCN*/sa_angle_around_axis(p1, p2, from, to)
  529.  
  530.   ads_point p1, p2;
  531.   ads_point from, to;
  532. {
  533.     ads_point nor1, nor2;
  534.     ads_point v, v1, v2;
  535.     double    l1, l2;
  536.     double    angle;
  537.     double    cosa;
  538.  
  539.     if (sa_points_are_collinear(p1, p2, from) ||
  540.         sa_points_are_collinear(p1, p2, to)) {
  541.         return(0.0);
  542.     }
  543.  
  544.     SUB_PNT(v, p2, p1);
  545.  
  546.     SUB_PNT(v1, from, p1);
  547.     SUB_PNT(v2, to  , p1);
  548.  
  549.     sa_cross(nor1, v1, v); l1 = LENGTH(nor1);
  550.     sa_cross(nor2, v2, v); l2 = LENGTH(nor2);
  551.  
  552.     cosa  = DOTPROD(nor1, nor2) / (l1 * l2);
  553.     angle = acos(cosa);
  554.  
  555.     if (sa_det(v, v1, v2) < 0.0)
  556.         angle = -angle;
  557.  
  558.     if (angle <  0.0)
  559.         angle += 2*PI;
  560.     if (angle > 2*PI)
  561.         angle -= 2*PI;
  562.  
  563.     return(angle);
  564. } /*sa_angle_around_axis*/
  565.  
  566.  
  567. /****************************************************************************/
  568. /*.doc sa_orientate_cs_upwards(external) */
  569. /*+
  570.   Orientates the given coordinate system, defined by four points (origin,
  571.   xaxis, yaxis and zaxis), so that its z-axis (from origin to point zaxis)
  572.   goes upwards, that is in the direction of the Z-axis of the current UCS.
  573.  
  574.   If the z-axis of the given coordinates system lies in the XY plane of the
  575.   current UCS, then the orientation is determined according to either the X
  576.   or Y axis of the current UCS, depending on to which axis is the given
  577.   z-axis more parallel.
  578. -*/
  579. /****************************************************************************/
  580.  
  581.  
  582. void
  583. /*FCN*/sa_orientate_cs_upwards(origin, xaxis, yaxis, zaxis)
  584.  
  585.   ads_point origin;                   /* Point at origin          */
  586.   ads_point xaxis, yaxis, zaxis;      /* Point on X, Y and Z axis */
  587. {
  588.     double    len;
  589.     int       reverse;
  590.     ads_point p;
  591.  
  592.     len = DISTANCE(origin, zaxis);
  593.  
  594.     if (fabs(origin[Z] - zaxis[Z]) / len >= ARBBOUND)
  595.         reverse = (origin[Z] > zaxis[Z]);
  596.     else
  597.     if (fabs(origin[X] - zaxis[X]) >= fabs(origin[Y] - zaxis[Y]))
  598.         reverse = (origin[X] > zaxis[X]);
  599.     else
  600.         reverse = (origin[Y] > zaxis[Y]);
  601.  
  602.     if (reverse) {
  603.         CPY_PNT(p,      origin);
  604.         CPY_PNT(origin, zaxis);
  605.         CPY_PNT(zaxis,  p);
  606.  
  607.         CPY_PNT(p,     xaxis);
  608.         CPY_PNT(xaxis, yaxis);
  609.         CPY_PNT(yaxis, p);
  610.     }
  611. } /*sa_orientate_cs_upwards*/
  612.  
  613.  
  614. /****************************************************************************/
  615. /*.doc sa_is_planar_pline(external) */
  616. /*+
  617.   Retruns TRUE if the pline having the given vertex is a planar 2D polyline,
  618.   otherwise returns FALSE. The output argument 'normal' will contain the
  619.   entity normal vector.
  620. -*/
  621. /****************************************************************************/
  622.  
  623.  
  624. int
  625. /*FCN*/sa_is_planar_pline(vertex_name, normal)
  626.  
  627.   ads_name  vertex_name;
  628.   ads_point normal;
  629. {
  630.     ads_name      pline_name;
  631.     int           flags = 8;    /* Just in case that group 70 is not found */
  632.     int           success;
  633.     struct resbuf *rb, *rb_rel;
  634.  
  635.     normal[X] = normal[Y] = normal[Z] = 0.0;
  636.  
  637.     success = sa_pline_name_from_vertex_name(vertex_name, pline_name);
  638.     if (success != RTNORM)
  639.         return(FALSE);
  640.  
  641.     rb = rb_rel = ads_entget(pline_name);
  642.  
  643.     while (rb != NULL) {
  644.         if (rb->restype == 70) {
  645.             flags = rb->resval.rint;
  646.         } else if (rb ->restype == 210) {
  647.             CPY_PNT(normal, rb->resval.rpoint);
  648.         }
  649.         rb = rb->rbnext;
  650.     }
  651.  
  652.     ads_relrb(rb_rel);
  653.  
  654.     return((flags & (8 + 16 + 64)) == 0);
  655. } /*sa_is_planar_pline*/
  656.  
  657.  
  658. /****************************************************************************/
  659. /*.doc sa_get_pline_segment_data(external) */
  660. /*+
  661.   Returns the endpoints p1 and p2, center, radius and normal vector of
  662.   a polyline segment, given by its name (name of VERTEX entity) and by vertex
  663.   entity data list of result buffers.
  664.  
  665.   If the pline segment is straight, then center contains the midpoint of
  666.   the segment and radius is 0.0.
  667.  
  668.   All the returned coordinates are expressed in ECS.
  669.  
  670.   Function returns one of the standard ADS result codes.
  671. -*/
  672. /****************************************************************************/
  673.  
  674.  
  675. int
  676. /*FCN*/sa_get_pline_segment_data(plseg_name, plseg_rb, p1, p2,
  677.                                  center, radius, normal)
  678.  
  679.   ads_name      plseg_name;      /* Name of pline segment (vertex)          */
  680.   struct resbuf *plseg_rb;       /* Vertex data as a list of result buffers */
  681.  
  682.   ads_point     p1, p2;          /* Returned endpoints of the segment       */
  683.   ads_point     center;          /* Returned center of arc segment          */
  684.   double        *radius;         /* Returned radius of arc segment          */
  685.   ads_point     normal;          /* Entity normal vector                    */
  686. {
  687.     int           success;
  688.     double        bulge;
  689.     struct resbuf *rb;
  690.     struct resbuf *next_rb, *first_rb;
  691.     ads_name      next_name, first_name;
  692.     ads_name      pline_name;
  693.     double        f, dist;
  694.  
  695.     success = RTNORM;
  696.     next_rb = first_rb = NULL;
  697.  
  698.     /* Check whether it is realy a planar non-splined 2D polyline */
  699.  
  700.     if (!sa_is_planar_pline(plseg_name, normal))
  701.         return(RTREJ);
  702.  
  703.     /* Get the first point and bulge */
  704.  
  705.     bulge = 0.0;
  706.     rb = plseg_rb;
  707.  
  708.     while (rb != NULL) {
  709.         if (rb->restype == 42) {
  710.             bulge = rb->resval.rreal;
  711.         } else if (rb->restype == 10) {
  712.             CPY_PNT(p1, rb->resval.rpoint);
  713.         }
  714.         rb = rb->rbnext;
  715.     } /*while*/
  716.  
  717.     /* Go to the next vertex */
  718.  
  719.     success = ads_entnext(plseg_name, next_name);
  720.     if (success != RTNORM)
  721.         return(RTERROR);
  722.  
  723.     next_rb = ads_entget(next_name);
  724.     if (next_rb == NULL)
  725.         return(RTERROR);
  726.  
  727.     rb = next_rb->rbnext;
  728.     if (rb->restype != 0) {
  729.         success = RTERROR;
  730.         goto Cleanup;
  731.     }
  732.  
  733.     /* If it is the last segment of closed entity then go to first segment */
  734.  
  735.     if (strcmp(rb->resval.rstring, /* NT */"SEQEND") == 0) {
  736.  
  737.         while ((rb != NULL) && (rb->restype != -2))
  738.             rb = rb->rbnext;
  739.  
  740.         if (rb == NULL) {
  741.             success = RTERROR;
  742.             goto Cleanup;
  743.         }
  744.  
  745.         pline_name[0] = rb->resval.rlname[0];
  746.         pline_name[1] = rb->resval.rlname[1];
  747.  
  748.         success = ads_entnext(pline_name, first_name);
  749.         if (success != RTNORM) {
  750.             success = RTERROR;
  751.             goto Cleanup;
  752.         }
  753.  
  754.         first_rb = ads_entget(first_name);
  755.         if (first_rb == NULL) {
  756.             success = RTERROR;
  757.             goto Cleanup;
  758.         }
  759.  
  760.         rb = first_rb->rbnext;
  761.         if (rb->restype != 0) {
  762.             success = RTERROR;
  763.             goto Cleanup;
  764.         }
  765.     } else if (strcmp(rb->resval.rstring, "VERTEX") != 0) {
  766.         success = RTERROR;
  767.         goto Cleanup;
  768.     }
  769.  
  770.     /* Get second point of either the next or the first vertex */
  771.  
  772.     while ((rb != NULL) && (rb->restype != 10))
  773.         rb = rb->rbnext;
  774.  
  775.     if (rb == NULL) {
  776.         success = RTERROR;
  777.         goto Cleanup;
  778.     }
  779.  
  780.     CPY_PNT(p2, rb->resval.rpoint);
  781.  
  782.  
  783.     /* Calculate center and radius of the pline arc segment */
  784.  
  785.     if (fabs(bulge) < ZERO_BULGE) {
  786.         *radius = 0.0;
  787.         ADD_PNT(center, p1, p2);
  788.         center[X] /= 2.0;
  789.         center[Y] /= 2.0;
  790.         center[Z] /= 2.0;
  791.     } else {
  792.         dist = DISTANCE(p1, p2);
  793.         *radius = fabs(0.25 * dist * (bulge + 1.0 / bulge));
  794.  
  795.         f = -0.25 * (bulge - 1/bulge);
  796.         center[X] = (p1[X] + p2[X])/2 + f*(p1[Y] - p2[Y]);
  797.         center[Y] = (p1[Y] + p2[Y])/2 + f*(p2[X] - p1[X]);
  798.         center[Z] = (p1[Z] + p2[Z])/2;
  799.     }
  800.     success = RTNORM;
  801.  
  802. Cleanup:
  803.  
  804.     if (next_rb  != NULL)
  805.         ads_relrb(next_rb);
  806.     if (first_rb != NULL)
  807.         ads_relrb(first_rb);
  808.  
  809.     return(success);
  810. } /*sa_get_pline_segment_data*/
  811.  
  812.  
  813. /****************************************************************************/
  814. /*.doc sa_pline_name_from_vertex_name(external) */
  815. /*+
  816.   Gives polyline name from a given name of a polyline segment (VERTEX).
  817.  
  818.   Function returns one of the standard ADS result codes.
  819. -*/
  820. /****************************************************************************/
  821.  
  822.  
  823. int
  824. /*FCN*/sa_pline_name_from_vertex_name(vertex_name, pline_name)
  825.  
  826.   ads_name vertex_name;               /* Name of polyline segment (VERTEX) */
  827.   ads_name pline_name;                /* Returned name of the polyline     */
  828. {
  829.     ads_name      name;
  830.     struct resbuf *rb;
  831.     int           success;
  832.  
  833.     ads_name_set(vertex_name, name);
  834.  
  835.     for (;;) {
  836.         success = ads_entnext(name, name);
  837.         if (success != RTNORM)
  838.             return(RTERROR);
  839.  
  840.         rb = ads_entget(name);
  841.         if ((rb == NULL) || (rb->rbnext == NULL) ||
  842.             (rb->rbnext->restype != 0)) {
  843.             ads_relrb(rb);
  844.             return(RTERROR);
  845.         }
  846.  
  847.         if (strcmp(rb->rbnext->resval.rstring, /* NT */"SEQEND") == 0) {
  848.             struct resbuf *rel_rb;
  849.  
  850.             rel_rb = rb;
  851.             rb = rb->rbnext->rbnext;
  852.  
  853.             while (rb->restype != -2)
  854.                 rb = rb->rbnext;
  855.  
  856.             ads_name_set(rb->resval.rlname, pline_name);
  857.  
  858.             ads_relrb(rel_rb);
  859.             return(RTNORM);
  860.         } /*if*/
  861.  
  862.         ads_relrb(rb);
  863.         if (success != RTNORM)
  864.             return(RTERROR);
  865.     } /*forever*/
  866. } /*sa_pline_name_from_vertex_name*/
  867.  
  868.  
  869. /****************************************************************************/
  870. /*.doc sa_tranform_pt(external) */
  871. /*+
  872.   Transforms given point p1 by 3x4 matrix 'm'. Transformed point is returned
  873.   in point p2.
  874. -*/
  875. /****************************************************************************/
  876.  
  877.  
  878. void
  879. /*FCN*/sa_transform_pt(m, p1, p2)
  880.  
  881.   ads_point m[4];
  882.   ads_point p1,p2;
  883. {
  884.     ads_point p;
  885.  
  886.     CPY_PNT(p, p1);
  887.  
  888.     p2[X] = m[X][X] * p[X] + m[Y][X] * p[Y] + m[Z][X] * p[Z] + m[3][X];
  889.     p2[Y] = m[X][Y] * p[X] + m[Y][Y] * p[Y] + m[Z][Y] * p[Z] + m[3][Y];
  890.     p2[Z] = m[X][Z] * p[X] + m[Y][Z] * p[Y] + m[Z][Z] * p[Z] + m[3][Z];
  891.  
  892. } /*sa_transform_pt*/
  893.  
  894.  
  895. /****************************************************************************/
  896. /*.doc sa_normalize(external) */
  897. /*+
  898.   Normalizes given vector v. Returns FALSE is the vector is nearly zero.
  899. -*/
  900. /****************************************************************************/
  901.  
  902.  
  903. int
  904. /*FCN*/sa_normalize(v)
  905.  
  906.   ads_point v;
  907. {
  908.     double len;
  909.  
  910.     len = LENGTH(v);
  911.  
  912.     if (len < EPS)
  913.         return(FALSE);
  914.  
  915.     v[X] /= len;
  916.     v[Y] /= len;
  917.     v[Z] /= len;
  918.  
  919.     return(TRUE);
  920. } /*sa_normalize*/
  921.  
  922.  
  923. /****************************************************************************/
  924. /*.doc sa_make_arb_matrix(external) */
  925. /*+
  926.   Makes arbitrary matrix 'm' for direction of z-axis 'zaxis'.
  927.  
  928.   Function returns one of the standard ADS result codes.
  929. -*/
  930. /****************************************************************************/
  931.  
  932.  
  933. int
  934. /*FCN*/sa_make_arb_matrix(zaxis, m)
  935.  
  936.   ads_point zaxis;                    /* Given direction of z-axis */
  937.   ads_point m[4];                     /* Returned arbitrary matrix */
  938. {
  939.     static ads_point unitmat[3] = {{1.0, 0.0, 0.0},
  940.                                    {0.0, 1.0, 0.0},
  941.                                    {0.0, 0.0, 1.0}};
  942.     int ok;
  943.  
  944.     CPY_PNT(m[Z], zaxis);
  945.     ok = sa_normalize(m[Z]);
  946.  
  947.     if (!ok)
  948.         return(RTERROR);
  949.  
  950.     if ((fabs(m[Z][X]) < ARBBOUND) && (fabs(m[Z][Y]) < ARBBOUND))
  951.         sa_cross(m[X], unitmat[Y], m[Z]);
  952.     else
  953.         sa_cross(m[X], unitmat[Z], m[Z]);
  954.  
  955.     sa_normalize(m[X]);
  956.  
  957.     sa_cross(m[Y], m[Z], m[X]);
  958.     sa_normalize(m[Y]);
  959.  
  960.     m[3][X] = m[3][Y] = m[3][Z] = 0.0;  /* No translation */
  961.  
  962.     return(RTNORM);
  963. } /*sa_make_arb_matrix*/
  964.  
  965.  
  966. /****************************************************************************/
  967. /*.doc sa_get_cs_of_picked_entity(external) */
  968. /*+
  969.   Function prompts to pick an entity (line, arc, circle, 2D pline segment)
  970.   and returns its axis or plane.
  971.  
  972.   axis_required: TRUE  => returns axis in two points origin and zaxis.
  973.                  FALSE => returns plane in three points origin, xaxis and yaxis
  974.  
  975.   The plane may also be considered a coordinates system:
  976.  
  977.   origin ... Point at the origin.
  978.   xaxis  ... Point on the positive portion of the X-axis.
  979.   yaxis  ... Point in the halfplane of the positive Y-axis.
  980.  
  981.   The axis or plane is obtained from the entity picked as follows:
  982.  
  983.   Axis:
  984.   ----
  985.   LINE        ... The endpoints of the line.
  986.   ARC, CIRCLE ... The axis of the arc or circle (perpendicular to the plane
  987.                   of the arc).
  988.   PLINE       ... Handled either as an arc or as a line depending on the
  989.                   type of the picked pline segment.
  990.  
  991.   Plane:
  992.   -----
  993.   ARC, CIRCLE ... The plane of the arc or circle, origin at the center.
  994.   PLINE       ... arc segment      -> handled as an arc,
  995.                   straight segment -> plane of the polyline, origin at the
  996.                                       endpoint closer to the picked point.
  997.  
  998.   The points xaxis and yaxix are calculated based on the arbitrary
  999.   axis algorithm.
  1000.  
  1001.   All returned points are expressed in the current UCS. Picking nested
  1002.   entities is properly handled and the returned axis/plane is the axis/plane
  1003.   of the nexted entity itself, not of the enclosing block.
  1004.  
  1005.   Function returns one of the standard ADS result codes.
  1006. -*/
  1007. /****************************************************************************/
  1008.  
  1009.  
  1010. int
  1011. /*FCN*/sa_get_cs_of_picked_entity(prompt, axis_required,
  1012.                                   origin, xaxis, yaxis, zaxis)
  1013.  
  1014.   char      *prompt;                      /* Prompt (optional)        */
  1015.   int       axis_required;                /* TRUE==Axis, FALSE==Plane */
  1016.   ads_point origin, xaxis, yaxis, zaxis;  /* Returned points          */
  1017. {
  1018.     int               success;
  1019.     ads_name          ent_name;
  1020.     struct resbuf     *ent_rb;
  1021.     ads_point         m[4];
  1022.     struct resbuf     *blocks;
  1023.     struct resbuf     *rb;
  1024.     ads_point         pick_pt;
  1025.     int               ent_type;
  1026.     int               nested_entity;
  1027.     ads_point         normal;
  1028.  
  1029.     success = RTNORM;
  1030.     ent_rb = blocks = NULL;
  1031.  
  1032.     normal[X] = normal[Y] = normal[Z] = 0.0;
  1033.  
  1034.     /* Pick an entity */
  1035.  
  1036. Pick:
  1037.  
  1038.     if (prompt != NULL) {
  1039.         success = ads_nentsel(prompt, ent_name, pick_pt, m, &blocks);
  1040.     } else if (axis_required) {
  1041. success = ads_nentsel("\n¼D┐∩ñ@íu╜uívíBíu╢ΩívíBíu⌐tív⌐╬íu2D╗EªX╜uív▓╒¼q:\n",
  1042.                       ent_name, pick_pt, m, &blocks);
  1043.     } else {
  1044. success = ads_nentsel("\n¼D┐∩ñ@íu╢ΩívíBíu⌐tív⌐╬íu2D╗EªX╜uív▓╒¼q:\n",
  1045.                       ent_name, pick_pt, m, &blocks);
  1046.     }
  1047.  
  1048.     if ((success == RTCAN) || (success == RTREJ))
  1049.         return(success);
  1050.  
  1051.     if (success != RTNORM) {
  1052.         ads_printf("\n¿S┐∩¿∞╣╧ñ╕íC\n\n");
  1053.         goto Pick;
  1054.     }
  1055.  
  1056.     /* Set nested_entity variable, erase list of enclosing blocks */
  1057.  
  1058.     nested_entity = (blocks != NULL);
  1059.     if (nested_entity)
  1060.         ads_relrb(blocks);
  1061.  
  1062.     /* Get the list of result buffers for the picked entity */
  1063.  
  1064.     ent_rb = ads_entget(ent_name);
  1065.     if (ent_rb == NULL) {
  1066.         success = RTERROR;
  1067.         goto Cleanup;
  1068.     }
  1069.  
  1070.     rb = ent_rb->rbnext;
  1071.     if (rb->restype != 0) {
  1072.         success = RTERROR;
  1073.         goto Cleanup;
  1074.     }
  1075.  
  1076.     /* Find out which type of entity has been picked */
  1077.  
  1078.     if (strcmp(rb->resval.rstring, /* NT */"LINE")   == 0)
  1079.         ent_type = 1;
  1080.     else
  1081.     if (strcmp(rb->resval.rstring, /* NT */"CIRCLE") == 0)
  1082.         ent_type = 2;
  1083.     else
  1084.     if (strcmp(rb->resval.rstring, /* NT */"ARC")    == 0)
  1085.         ent_type = 3;
  1086.     else
  1087.     if (strcmp(rb->resval.rstring, "VERTEX") == 0)
  1088.         ent_type = 4;
  1089.     else {
  1090.  
  1091. Improper_entity:
  1092.  
  1093.         ads_printf("\n┐∩⌐w¬║íu╣╧ñ╕├■ºOívñúÑ┐╜TíC\n\n");
  1094.         ads_relrb(ent_rb);
  1095.         goto Pick;
  1096.     }
  1097.  
  1098.     if ((ent_type == 1) && (!axis_required))
  1099.         goto Improper_entity;
  1100.  
  1101.     /* Get points origin, xaxis, yaxis, zaxis from the picked entity */
  1102.  
  1103.     if (ent_type == 1 /*line*/) {
  1104.  
  1105.         while (rb != NULL) {
  1106.             if (rb->restype == 10)
  1107.                 CPY_PNT(origin,rb->resval.rpoint);
  1108.             else if (rb->restype == 11)
  1109.                 CPY_PNT(zaxis,rb->resval.rpoint);
  1110.             rb = rb->rbnext;
  1111.         } /*while*/
  1112.  
  1113.         CPY_PNT(xaxis, origin);
  1114.         CPY_PNT(yaxis, origin);
  1115.  
  1116.     } else if ((ent_type == 2 /*circle*/) || (ent_type == 3 /*arc*/)) {
  1117.  
  1118.         while (rb != NULL) {
  1119.             if (rb->restype == 10)
  1120.                 CPY_PNT(origin, rb->resval.rpoint);
  1121.             else if (rb->restype == 210)
  1122.                 CPY_PNT(normal, rb->resval.rpoint);
  1123.             rb = rb->rbnext;
  1124.         } /*while*/
  1125.  
  1126.         CPY_PNT(xaxis, origin); xaxis[X] += 1.0;
  1127.         CPY_PNT(yaxis, origin); yaxis[Y] += 1.0;
  1128.         CPY_PNT(zaxis, origin); zaxis[Z] += 1.0;
  1129.  
  1130.     } else {
  1131.  
  1132.         /* Polyline */
  1133.  
  1134.         ads_point p1, p2;
  1135.         double    radius;
  1136.  
  1137.         success = sa_get_pline_segment_data(ent_name, ent_rb, p1, p2,
  1138.                                             origin, &radius, normal);
  1139.         if (success == RTREJ) {
  1140.             ads_printf("\nÑ▓╢╖¼░íu2D╗EªX╜uívíC\n\n");
  1141.             ads_relrb(ent_rb);
  1142.             goto Pick;
  1143.         } else if (success != RTNORM) {
  1144.             success = RTERROR;
  1145.             goto Cleanup;
  1146.         }
  1147.  
  1148.         /* Exchange 'p1' and 'p2' to make 'p1' visually closer to
  1149.            the picked point 'pick_pt' */
  1150.  
  1151.         {
  1152.             ads_point pd1,pd2;
  1153.  
  1154.             sa_e2u(p1, ent_name, nested_entity, m, normal, pd1);
  1155.             sa_e2u(p2, ent_name, nested_entity, m, normal, pd2);
  1156.  
  1157.             if (sa_visual_distance(pd1, pick_pt) >
  1158.                 sa_visual_distance(pd2, pick_pt)) {
  1159.                 ads_point p;
  1160.                 CPY_PNT(p,  p1);
  1161.                 CPY_PNT(p1, p2);
  1162.                 CPY_PNT(p2, p );
  1163.             }
  1164.         }
  1165.  
  1166.         if (radius == 0.0) /*straight segment*/ {
  1167.  
  1168.             if (axis_required) {
  1169.                 CPY_PNT(origin,p1);
  1170.                 CPY_PNT(zaxis, p2);
  1171.                 CPY_PNT(xaxis, origin);
  1172.                 CPY_PNT(yaxis, origin);
  1173.             } else /*plane required*/ {
  1174.                 CPY_PNT(origin,p1    );
  1175.                 CPY_PNT(xaxis, origin);  xaxis[X] += 1.0;
  1176.                 CPY_PNT(yaxis, origin);  yaxis[Y] += 1.0;
  1177.                 CPY_PNT(zaxis, origin);  zaxis[Z] += 1.0;
  1178.             }
  1179.         } else /*arc segment*/ {
  1180.             CPY_PNT(xaxis, origin);  xaxis[X] += 1.0;
  1181.             CPY_PNT(yaxis, origin);  yaxis[Y] += 1.0;
  1182.             CPY_PNT(zaxis, origin);  zaxis[Z] += 1.0;
  1183.         }
  1184.     }                                 /*else pline*/
  1185.  
  1186.  
  1187.     if (DISTANCE(origin, zaxis) < EPS) {
  1188.         ads_printf("\n┐∩¿∞íuºφ¿ε▓úÑ═ív¬║╣╧ñ╕íC\n\n");
  1189.         ads_relrb(ent_rb);
  1190.         goto Pick;
  1191.     }
  1192.  
  1193.     /* Transform 'origin', 'xaxis', 'yaxis', 'zaxis' from ECS to UCS */
  1194.  
  1195.     sa_e2u(origin, ent_name, nested_entity, m, normal, origin);
  1196.     sa_e2u(xaxis,  ent_name, nested_entity, m, normal, xaxis );
  1197.     sa_e2u(yaxis,  ent_name, nested_entity, m, normal, yaxis );
  1198.     sa_e2u(zaxis,  ent_name, nested_entity, m, normal, zaxis );
  1199.  
  1200.     success = RTNORM;
  1201.  
  1202. Cleanup:
  1203.  
  1204.    /* Erase the list of result buffers */
  1205.  
  1206.     if (ent_rb != NULL)
  1207.         ads_relrb(ent_rb);
  1208.  
  1209.     return(success);
  1210. } /*sa_get_cs_of_picked_entity*/
  1211.  
  1212.  
  1213. /****************************************************************************/
  1214. /*.doc sa_snap(external) */
  1215. /*+
  1216.   Prompts to pick an entity and gives its snap point.
  1217.  
  1218.   Function returns one of the standard ADS result codes.
  1219. -*/
  1220. /****************************************************************************/
  1221.  
  1222.  
  1223. int
  1224. /*FCN*/sa_snap(prompt, mode, p)
  1225.  
  1226.   char      *prompt;                  /* Prompt (optional)       */
  1227.   char      *mode;                    /* "END", "MID", "CEN" etc.*/
  1228.   ads_point p;                        /* Returned snap point     */
  1229. {
  1230.     int      success;
  1231.     ads_name ent_name;
  1232.  
  1233. Pick:
  1234.  
  1235.     sa_make_pickbox_equal_to_aperture(TRUE);
  1236.     success = ads_entsel(prompt, ent_name, p);
  1237.     sa_make_pickbox_equal_to_aperture(FALSE);
  1238.  
  1239.     if ((success == RTCAN) || (success == RTREJ)) {
  1240.         return(success);
  1241.     }
  1242.     if (success != RTNORM) {
  1243.         ads_printf("\nÑ╝┐∩¿∞╣╧ñ╕íC\n\n");
  1244.         goto Pick;
  1245.     }
  1246.  
  1247.     success = ads_osnap(p, mode, p);
  1248.     if (success != RTNORM) {
  1249.         ads_printf("\n¼D┐∩¬║íu╣╧ñ╕├■ºOívñúÑ┐╜TíC\n\n");
  1250.         goto Pick;
  1251.     }
  1252.  
  1253.     return(RTNORM);
  1254. } /*sa_snap*/
  1255.  
  1256.  
  1257. /****************************************************************************/
  1258. /*.doc sa_uniform_scaling_factor(external) */
  1259. /*+
  1260.   Function extracts the scaling factor from matrix 'm'. If
  1261.   this matrix represents uniform scaling (the same scaling in
  1262.   all directions) then it returns this (positive) scaling factor.
  1263.   Otherwise it returns value -1.0.
  1264. -*/
  1265. /****************************************************************************/
  1266.  
  1267.  
  1268. double
  1269. /*FCN*/sa_uniform_scaling_factor(m)
  1270.  
  1271.   ads_point  m[4];
  1272. {
  1273.     double sx,sy,sz,s;
  1274.  
  1275.     sx = sqrt(SQR(m[X][X]) + SQR(m[X][Y]) + SQR(m[X][Z]));
  1276.     sy = sqrt(SQR(m[Y][X]) + SQR(m[Y][Y]) + SQR(m[Y][Z]));
  1277.     sz = sqrt(SQR(m[Z][X]) + SQR(m[Z][Y]) + SQR(m[Z][Z]));
  1278.     s = (sx + sy + sz) / 3;
  1279.  
  1280.     if ((fabs(s) < EPS) ||
  1281.         (fabs(s-sx)/s + fabs(s-sy)/s + fabs(s-sy)/s > 1e-5))
  1282.         return(-1.0);
  1283.     else
  1284.         return(s);
  1285.  
  1286. } /*sa_uniform_scaling_factor*/
  1287.  
  1288.  
  1289. /****************************************************************************/
  1290. /*.doc sa_plane_equation(external) */
  1291. /*+
  1292.   Function calcuates the plane eqation from:
  1293.  
  1294.   - 3 points p1, p2, p3                    (pts3 == TRUE)
  1295.   - plane point p1 and point on normal p2  (pts3 == FALSE)
  1296.  
  1297.   The unit normal vector to the  plane is returned in 'n' and the
  1298.   constant coefficient is returned in 'd', according to the implicit
  1299.   plane equation:
  1300.  
  1301.             n[X]*x + n[Y]*y + n[Z]*z + d == 0.0
  1302.  
  1303.   Function returns one of the standard ADS result codes.
  1304. -*/
  1305. /****************************************************************************/
  1306.  
  1307.  
  1308. int
  1309. /*FCN*/sa_plane_equation(pts3, p1, p2, p3, n, d)
  1310.  
  1311.   int       pts3;             /* TRUE==3 points, FALSE==pt & normal pt */
  1312.   ads_point p1, p2, p3;
  1313.   ads_point n;                /* Returned unit normal vector           */
  1314.   double    *d;               /* Returned constant coefficient         */
  1315. {
  1316.     ads_point v1, v2, nn;
  1317.     double    dd;
  1318.     int       ok;
  1319.  
  1320.     if (pts3) /*3 points*/ {
  1321.         SUB_PNT(v1, p2, p1);
  1322.         SUB_PNT(v2, p3, p1);
  1323.         sa_cross(nn, v1, v2);
  1324.         ok = sa_normalize(nn);
  1325.         if (!ok)
  1326.             return(RTERROR);
  1327.         dd = -(DOTPROD(nn, p1) + DOTPROD(nn, p2) + DOTPROD(nn, p3)) / 3;
  1328.     } else /*2 points*/ {
  1329.         SUB_PNT(nn, p2, p1);
  1330.         ok = sa_normalize(nn);
  1331.         if (!ok)
  1332.             return(RTERROR);
  1333.         dd = -DOTPROD(nn, p1);
  1334.     }
  1335.  
  1336.     CPY_PNT(n, nn);
  1337.     *d = dd;
  1338.     return(RTNORM);
  1339. } /*sa_plane_equation*/
  1340.  
  1341.  
  1342. /****************************************************************************/
  1343. /*.doc sa_u2w(external) */
  1344. /*+
  1345.   Transforms a given point from UCS to WCS.
  1346.  
  1347.   Function returns one of the standard ADS result codes.
  1348. -*/
  1349. /****************************************************************************/
  1350.  
  1351.  
  1352. int
  1353. /*FCN*/sa_u2w(p1, p2)
  1354.  
  1355.   ads_point p1,p2;
  1356. {
  1357.     int           success;
  1358.     struct resbuf wcs,ucs;
  1359.  
  1360.     wcs.restype     = RTSHORT;
  1361.     wcs.resval.rint = 0;
  1362.     ucs.restype     = RTSHORT;
  1363.     ucs.resval.rint = 1;
  1364.  
  1365.     success = ads_trans(p1, &ucs, &wcs, 0, p2);
  1366.  
  1367.     return(success);
  1368. } /*sa_u2w*/
  1369.  
  1370.  
  1371. /****************************************************************************/
  1372. /*.doc sa_w2u(external) */
  1373. /*+
  1374.   Transforms a given point from WCS to UCS.
  1375.  
  1376.   Function returns one of the standard ADS result codes.
  1377. -*/
  1378. /****************************************************************************/
  1379.  
  1380.  
  1381. int
  1382. /*FCN*/sa_w2u(p1, p2)
  1383.  
  1384.   ads_point p1,p2;
  1385. {
  1386.     int           success;
  1387.     struct resbuf wcs,ucs;
  1388.  
  1389.     wcs.restype     = RTSHORT;
  1390.     wcs.resval.rint = 0;
  1391.     ucs.restype     = RTSHORT;
  1392.     ucs.resval.rint = 1;
  1393.  
  1394.     success = ads_trans(p1, &wcs, &ucs, 0, p2);
  1395.  
  1396.     return(success);
  1397. } /*sa_w2u*/
  1398.  
  1399.  
  1400. /****************************************************************************/
  1401. /*.doc sa_get_radius_of_picked_entity(external) */
  1402. /*+
  1403.   Returns radius of a picked entity (arc, circle or 2D polyline segment).
  1404.   Nested entities are properly handled, that is you may pick an entity
  1405.   nested inside a block.
  1406.  
  1407.   Function returns one of the standard ADS result codes.
  1408. -*/
  1409. /****************************************************************************/
  1410.  
  1411.  
  1412. int
  1413. /*FCN*/sa_get_radius_of_picked_entity(prompt, radius)
  1414.  
  1415.   char   *prompt;                     /* Prompt (optional) */
  1416.   double *radius;                     /* Returned radius   */
  1417. {
  1418.     int           success;
  1419.     int           entity_type;
  1420.     ads_name      ent_name;
  1421.     struct resbuf *ent_rb, *rb, *blocks;
  1422.     double        matrix[4][3];
  1423.     double        scale,rad;
  1424.     ads_point     pick_pt;
  1425.     ads_point     normal;
  1426.  
  1427.     /* Pick an entity */
  1428.  
  1429. Pick:
  1430.     success = ads_nentsel(prompt, ent_name, pick_pt, matrix, &blocks);
  1431.  
  1432.     if ((success == RTCAN) || (success == RTREJ)) {
  1433.         return(success);
  1434.     }
  1435.     if (success != RTNORM) {
  1436.         ads_printf("\nÑ╝┐∩¿∞╣╧ñ╕íC\n\n");
  1437.         goto Pick;
  1438.     }
  1439.  
  1440.     if (blocks != NULL) {
  1441.         ads_relrb(blocks);
  1442.  
  1443.         if ((scale = sa_uniform_scaling_factor(matrix)) < 0) {
  1444.         ads_printf("\n╣╧╕s¬║íuñ±¿╥ívñúñ@¡P, Ñb«|ñúªsªbíC\n\n");
  1445.             goto Pick;
  1446.         }
  1447.     } else {
  1448.         scale = 1.0;
  1449.     }
  1450.  
  1451.     /* Find out which type of entity has been picked */
  1452.  
  1453.     ent_rb = ads_entget(ent_name);
  1454.     if (ent_rb == NULL)
  1455.         return(RTERROR);
  1456.  
  1457.     rb = ent_rb->rbnext;
  1458.     if (rb->restype != 0) {
  1459.         ads_relrb(ent_rb);
  1460.         return(RTERROR);
  1461.     }
  1462.  
  1463.     if (strcmp(rb->resval.rstring, /* NT */"CIRCLE") == 0)
  1464.         entity_type = 1;
  1465.     else if (strcmp(rb->resval.rstring, /* NT */"ARC") == 0)
  1466.         entity_type = 2;
  1467.     else if (strcmp(rb->resval.rstring, /* NT */"VERTEX") == 0)
  1468.         entity_type = 3;
  1469.     else {
  1470.         ads_relrb(ent_rb);
  1471.         ads_printf("\n¼D┐∩¬║íu╣╧ñ╕├■ºOívñúÑ┐╜TíC\n\n");
  1472.         goto Pick;
  1473.     }
  1474.  
  1475.     /* Get the entity radius from the entity data */
  1476.  
  1477.     switch (entity_type) {
  1478.  
  1479.     case 1: /*circle*/
  1480.     case 2: /*arc*/
  1481.         while ((rb != NULL) && (rb->restype != 40))
  1482.             rb = rb->rbnext;
  1483.         if (rb == NULL) {
  1484.             ads_relrb(ent_rb);
  1485.             return(RTERROR);
  1486.         }
  1487.  
  1488.         rad = rb->resval.rreal;
  1489.         break;
  1490.  
  1491.     case 3: /*polyline*/
  1492.         {
  1493.             ads_point p1, p2, cen;
  1494.  
  1495.             success = sa_get_pline_segment_data(ent_name, ent_rb, p1, p2,
  1496.                                                 cen, &rad, normal);
  1497.             if (success == RTREJ) { /*Mesh, etc.*/
  1498.                 ads_relrb(ent_rb);
  1499.                 ads_printf("\nÑ▓╢╖¼░íu2D╗EªX╜uívíC\n\n");
  1500.                 goto Pick;
  1501.             } else if (success != RTNORM) {
  1502.                 ads_relrb(ent_rb);
  1503.                 return(RTERROR);
  1504.             }
  1505.             if (rad == 0.0) {
  1506.                 ads_relrb(ent_rb);
  1507.                 ads_printf("\nÑ▓╢╖¼D┐∩íu╗EªX╜uí╨⌐╖¼qívíC\n\n");
  1508.                 goto Pick;
  1509.             }
  1510.         }
  1511.         break;
  1512.     } /*switch*/
  1513.  
  1514.     *radius = scale * rad;
  1515.     return(RTNORM);
  1516.  
  1517. } /*sa_get_radius_of_picked_entity*/
  1518.  
  1519.  
  1520. /****************************************************************************/
  1521. /*.doc sa_visual_distance(external) */
  1522. /*+
  1523.   Returns visual distance (in display coordinate system) of two given
  1524.   points p1 and p2, expressed in current UCS.
  1525. -*/
  1526. /****************************************************************************/
  1527.  
  1528.  
  1529. double
  1530. /*FCN*/sa_visual_distance(p1, p2)
  1531.  
  1532.   ads_point p1,p2;
  1533. {
  1534.     ads_point     pd1, pd2;
  1535.     struct resbuf ucs, dcs;
  1536.     double        dist;
  1537.  
  1538.     ucs.restype     = RTSHORT;
  1539.     ucs.resval.rint = 1;
  1540.     dcs.restype     = RTSHORT;
  1541.     dcs.resval.rint = 2;
  1542.  
  1543.     ads_trans(p1, &ucs, &dcs, FALSE, pd1);
  1544.     ads_trans(p2, &ucs, &dcs, FALSE, pd2);
  1545.     pd1[Z] = pd2[Z] = 0.0;
  1546.     dist = DISTANCE(pd1, pd2);
  1547.  
  1548.     return(dist);
  1549. } /*sa_visual_distance*/
  1550.  
  1551.  
  1552. /****************************************************************************/
  1553. /*.doc sa_e2u(external) */
  1554. /*+
  1555.   Transform point from ECS to UCS (supports nested entities).
  1556.  
  1557.   Function returns one of the standard ADS result codes.
  1558. -*/
  1559. /****************************************************************************/
  1560.  
  1561.  
  1562. static int
  1563. /*FCN*/sa_e2u(p1, ent_name, nested, m, normal, p2)
  1564.  
  1565.   ads_point p1;       /* Point in ECS to be transformed                     */
  1566.   ads_name  ent_name; /* Entity name                                        */
  1567.   int       nested;   /* Is entity nested ?                                 */
  1568.   ads_point m[4];     /* Matrix from ads_nentsel()                          */
  1569.   ads_point normal;   /* Entity normal (for arc, circle), (0,0,0) otherwise */
  1570.   ads_point p2;       /* Resulting point in UCS                             */
  1571. {
  1572.     ads_point     arbm[4];
  1573.     struct resbuf ecs, ucs;
  1574.     int           success;
  1575.     ads_point     p;
  1576.  
  1577.     ecs.restype          = RTENAME;
  1578.     ecs.resval.rlname[0] = ent_name[0];
  1579.     ecs.resval.rlname[1] = ent_name[1];
  1580.  
  1581.     ucs.restype     = RTSHORT;
  1582.     ucs.resval.rint = 1;
  1583.  
  1584.     arbm[X][X] = 1.0; arbm[X][Y] = 0.0; arbm[X][Z] = 0.0;
  1585.     arbm[Y][X] = 0.0; arbm[Y][Y] = 1.0; arbm[Y][Z] = 0.0;
  1586.     arbm[Z][X] = 0.0; arbm[Z][Y] = 0.0; arbm[Z][Z] = 1.0;
  1587.     arbm[3][X] = 0.0; arbm[3][Y] = 0.0; arbm[3][Z] = 0.0;
  1588.  
  1589.     /* If normal is provided (for arc & circle), make arbitrary matrix */
  1590.  
  1591.     if (nested && (normal != NULL) && (LENGTH(normal) > EPS)) {
  1592.         sa_make_arb_matrix(normal, arbm);
  1593.     }
  1594.  
  1595.     if (!nested) {
  1596.         success = ads_trans(p1, &ecs, &ucs, 0, p);
  1597.     } else {
  1598.         /*ECS->MCS*/
  1599.  
  1600.         sa_transform_pt(arbm, p1, p);
  1601.  
  1602.         /*MCS->WCS*/
  1603.  
  1604.         sa_transform_pt(m, p, p);
  1605.  
  1606.         /*WCS->UCS*/
  1607.  
  1608.         success = sa_w2u(p, p);
  1609.     }
  1610.     CPY_PNT(p2, p);
  1611.  
  1612.     return(success);
  1613. } /*sa_e2u*/
  1614.  
  1615.  
  1616. /****************************************************************************/
  1617. /*.doc sa_normalize_angle(external) */
  1618. /*+
  1619.   Normalizes angle (in radians) to interval <0;2*PI).
  1620. -*/
  1621. /****************************************************************************/
  1622.  
  1623.  
  1624. void
  1625. /*FCN*/sa_normalize_angle(angle)
  1626.  
  1627.   double *angle;
  1628. {
  1629.     *angle = fmod(*angle, 2*PI);
  1630.     if (*angle < 0.0)
  1631.         *angle += 2*PI;
  1632. } /*sa_normalize_angle*/
  1633.  
  1634.  
  1635.