home *** CD-ROM | disk | FTP | other *** search
/ CDUTIL 13 / CDUTIL #13 Julio 1995.iso / windows / acadcom / ads / sample / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-08  |  46.3 KB  |  1,654 lines

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