(root)/
libredwg-0.13/
src/
geom.c
       1  /*****************************************************************************/
       2  /*  LibreDWG - free implementation of the DWG file format                    */
       3  /*                                                                           */
       4  /*  Copyright (C) 2019,2022-2023 Free Software Foundation, Inc.              */
       5  /*                                                                           */
       6  /*  This library is free software, licensed under the terms of the GNU       */
       7  /*  General Public License as published by the Free Software Foundation,     */
       8  /*  either version 3 of the License, or (at your option) any later version.  */
       9  /*  You should have received a copy of the GNU General Public License        */
      10  /*  along with this program.  If not, see <http://www.gnu.org/licenses/>.    */
      11  /*****************************************************************************/
      12  
      13  /*
      14   * geom.c: geometric projections from OCS
      15   * Note: There are certainly bugs lurking here. Not thoroughly tested yet.
      16   * For the properly exported variants see dwg_api instead, with the
      17   * dwg_geom_ prefix.
      18   * written by Reini Urban
      19   */
      20  
      21  #include "config.h"
      22  #include <string.h>
      23  // #include <stdio.h>
      24  #include <math.h>
      25  #include <dwg.h>
      26  #include "common.h"
      27  #include "geom.h"
      28  
      29  static void
      30  normalize (BITCODE_3DPOINT *out, BITCODE_3DPOINT pt)
      31  {
      32    double l = sqrt ((pt.x * pt.x) + (pt.y * pt.y) + (pt.z * pt.z));
      33    *out = pt;
      34    if (l != 1.0 && l != 0.0)
      35      {
      36        out->x = pt.x / l;
      37        out->y = pt.y / l;
      38        out->z = pt.z / l;
      39      }
      40  }
      41  
      42  static void
      43  cross (BITCODE_3DPOINT *out, BITCODE_3DPOINT pt1, BITCODE_3DPOINT pt2)
      44  {
      45    out->x = pt1.y * pt2.z - pt1.z * pt2.y;
      46    out->y = pt1.z * pt2.x - pt1.x * pt2.z;
      47    out->z = pt1.x * pt2.y - pt1.y * pt2.x;
      48  }
      49  
      50  // transform a 2D point via its OCS (extrusion or normal) to 2D
      51  void
      52  transform_OCS_2d (BITCODE_2DPOINT *out, BITCODE_2DPOINT pt, BITCODE_BE ext)
      53  {
      54    // [0,0,0] with preR13
      55    if (ext.x == 0.0 && ext.y == 0.0 && (ext.z == 1.0 || ext.z == 0.0))
      56      {
      57        *out = pt;
      58      }
      59    else if (ext.x == 0.0 && ext.y == 0.0 && ext.z == -1.0)
      60      {
      61        *out = pt;
      62        out->x = -out->x;
      63      }
      64    else
      65      {
      66        /* This is called the "Arbitrary Axis Algorithm" to calculate
      67           the OCS x-axis from the extrusion z-vector (the "normal") */
      68        BITCODE_3DPOINT ax, ay, az, be;
      69        memcpy (&be, &ext, sizeof (BITCODE_3DPOINT));
      70        normalize (&az, be);
      71        if ((fabs (az.x) < 1 / 64.0) && (fabs (az.y) < 1 / 64.0))
      72          {
      73            BITCODE_3DPOINT tmp = { 0.0, 1.0, 0.0 };
      74            cross (&tmp, tmp, az);
      75            normalize (&ax, tmp);
      76          }
      77        else
      78          {
      79            BITCODE_3DPOINT tmp = { 0.0, 0.0, 1.0 };
      80            cross (&tmp, tmp, az);
      81            normalize (&ax, tmp);
      82          }
      83        cross (&ay, az, ax);
      84        normalize (&ay, ay);
      85        out->x = pt.x * ax.x + pt.y * ax.y;
      86        out->y = pt.x * ay.x + pt.y * ay.y;
      87      }
      88    return;
      89  }
      90  
      91  // transform a 3D point via its OCS (extrusion or normal) to 3D
      92  void
      93  transform_OCS (BITCODE_3DPOINT *out, BITCODE_3DPOINT pt, BITCODE_BE ext)
      94  {
      95    if (ext.x == 0.0 && ext.y == 0.0 && ext.z == 1.0)
      96      {
      97        *out = pt;
      98      }
      99    else if (ext.x == 0.0 && ext.y == 0.0 && ext.z == -1.0)
     100      {
     101        *out = pt;
     102        out->x = -out->x;
     103      }
     104    else
     105      {
     106        /* This is called the "Arbitrary Axis Algorithm" to calculate
     107           the OCS x-axis from the extrusion z-vector */
     108        BITCODE_3DPOINT ax, ay, az, be;
     109        memcpy (&be, &ext, sizeof (BITCODE_3DPOINT));
     110        normalize (&az, be);
     111        if ((fabs (az.x) < 1 / 64.0) && (fabs (az.y) < 1 / 64.0))
     112          {
     113            BITCODE_3DPOINT tmp = { 0.0, 1.0, 0.0 };
     114            cross (&tmp, tmp, az);
     115            normalize (&ax, tmp);
     116          }
     117        else
     118          {
     119            BITCODE_3DPOINT tmp = { 0.0, 0.0, 1.0 };
     120            cross (&tmp, tmp, az);
     121            normalize (&ax, tmp);
     122          }
     123        cross (&ay, az, ax);
     124        normalize (&ay, ay);
     125        out->x = pt.x * ax.x + pt.y * ax.y + pt.z * ax.z;
     126        out->y = pt.x * ay.x + pt.y * ay.y + pt.z * ay.z;
     127        out->z = pt.x * az.x + pt.y * az.y + pt.z * az.z;
     128      }
     129    return;
     130  }
     131  
     132  // TODO: bulge -> arc for svg and ps.
     133  
     134  // endpoint of the angular vector from ctr, to angle (radian), for radius len
     135  void
     136  angle_vector_2d (BITCODE_2BD *out, BITCODE_2BD ctr, BITCODE_BD angle,
     137                   BITCODE_BD len)
     138  {
     139    out->x = ctr.x + (len * cos (angle));
     140    out->y = ctr.y + (len * sin (angle));
     141  }
     142  
     143  // Segmentation of arc,curves into plines for geojson.
     144  void
     145  arc_split (BITCODE_2BD *pts, const int num_pts, const BITCODE_2BD ctr,
     146             BITCODE_BD start_angle, BITCODE_BD end_angle, const BITCODE_BD len)
     147  {
     148    double ang, angd;
     149  #ifndef HAVE_NONNULL
     150    if (!pts)
     151      return;
     152  #endif
     153    while (start_angle > end_angle)
     154      end_angle += M_PI;
     155    // shoot vectors from ctr to ang
     156    ang = start_angle;
     157    angd = (end_angle - start_angle) / num_pts;
     158    while ((angd = (end_angle - start_angle) / (num_pts - 1)) < 0)
     159      start_angle += M_PI;
     160    // fprintf (stderr, "ctr (%g,%g) ang: %g - %g\n", ctr.x, ctr.y, ang,
     161    // end_angle);
     162    for (int i = 0; i < num_pts; i++, ang += angd)
     163      {
     164        BITCODE_2BD pt;
     165        angle_vector_2d (&pt, ctr, ang, len);
     166        // fprintf (stderr, "ang[%d] %g\n", i, ang);
     167        pts[i].x = pt.x;
     168        pts[i].y = pt.y;
     169      }
     170  }