LCOV - code coverage report
Current view: top level - pencil/source/draw - draw_svg_path_data.inl (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.63.2_covts Lines: 82.9 % 82 68
Test Date: 2025-05-01 10:10:14 Functions: 83.3 % 6 5

            Line data    Source code
       1              : /* File: draw_svg_path_data.inl; Copyright and License: see below */
       2              : 
       3              : #include "u8/u8_log.h"
       4              : #include <math.h>
       5              : #include <assert.h>
       6              : 
       7           28 : static inline void draw_svg_path_data_init( draw_svg_path_data_t *this_ )
       8              : {
       9           28 :     (*this_).dummy = 0;  /* prevent warnings on uninitialized usage */
      10           28 : }
      11              : 
      12           28 : static inline void draw_svg_path_data_destroy( draw_svg_path_data_t *this_ )
      13              : {
      14              : 
      15           28 : }
      16              : 
      17           28 : static inline u8_error_t draw_svg_path_data_parse_bounds ( const draw_svg_path_data_t *this_,
      18              :                                                            utf8stringviewtokenizer_t *tok_iterator,
      19              :                                                            geometry_rectangle_t *out_view_rect,
      20              :                                                            u8_error_info_t *out_err_info
      21              :                                                          )
      22              : {
      23           28 :     const geometry_rectangle_t dummy_target = { .left = 0.0, .top = 0.0, .width = 0.0, .height = 0.0 };
      24              :     const u8_error_t result
      25           28 :         = draw_svg_path_data_private_parse( this_,
      26              :                                             false,  /* draw */
      27              :                                             tok_iterator,
      28              :                                             out_view_rect,
      29              :                                             out_err_info,
      30              :                                             &dummy_target,
      31              :                                             NULL  /* cr */
      32              :                                           );
      33           28 :     return result;
      34              : }
      35              : 
      36            0 : static inline u8_error_t draw_svg_path_data_draw ( const draw_svg_path_data_t *this_,
      37              :                                                    utf8stringviewtokenizer_t *tok_iterator,
      38              :                                                    const geometry_rectangle_t *in_view_rect,
      39              :                                                    u8_error_info_t *out_err_info,
      40              :                                                    const geometry_rectangle_t *target_bounds,
      41              :                                                    cairo_t *cr
      42              :                                                  )
      43              : {
      44            0 :     geometry_rectangle_t non_const_view = *in_view_rect;
      45              :     const u8_error_t result
      46            0 :         = draw_svg_path_data_private_parse( this_,
      47              :                                             true,  /* draw */
      48              :                                             tok_iterator,
      49              :                                             &non_const_view,
      50              :                                             out_err_info,
      51              :                                             target_bounds,
      52              :                                             cr
      53              :                                           );
      54            0 :     return result;
      55              : }
      56              : 
      57           16 : static inline double draw_svg_path_data_private_get_angle ( const draw_svg_path_data_t *this_,
      58              :                                                             double u_x,
      59              :                                                             double u_y,
      60              :                                                             double v_x,
      61              :                                                             double v_y )
      62              : {
      63           16 :     const bool negative = (( u_x * v_y ) - ( u_y * v_x )) < 0.0;
      64           16 :     const double len_u = sqrt( ( u_x * u_x ) + ( u_y * u_y ) );
      65           16 :     const double len_v = sqrt( ( v_x * v_x ) + ( v_y * v_y ) );
      66           16 :     const double abs_angle = acos((( u_x * v_x ) + ( u_y * v_y )) / ( len_u * len_v ));
      67           16 :     return negative ? ( -abs_angle ) : abs_angle;
      68              : }
      69              : 
      70            8 : static inline u8_error_t draw_svg_path_data_private_get_arc_center ( const draw_svg_path_data_t *this_,
      71              :                                                                      double start_x,
      72              :                                                                      double start_y,
      73              :                                                                      double end_x,
      74              :                                                                      double end_y,
      75              :                                                                      bool large_arc,
      76              :                                                                      bool sweep_positive_dir,
      77              :                                                                      double r_x,
      78              :                                                                      double r_y,
      79              :                                                                      double phi,
      80              :                                                                      double *out_center_x,
      81              :                                                                      double *out_center_y,
      82              :                                                                      double *out_start_angle,
      83              :                                                                      double *out_delta_angle )
      84              : {
      85            8 :     U8_TRACE_BEGIN();
      86            8 :     assert( out_center_x != NULL );
      87            8 :     assert( out_center_y != NULL );
      88            8 :     assert( out_start_angle != NULL );
      89            8 :     assert( out_delta_angle != NULL );
      90            8 :     u8_error_t result = U8_ERROR_NONE;
      91              : 
      92              :     /* see https://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter */
      93              : 
      94              :     /* see B.2.5, step 2, eq 6.1 */
      95            8 :     r_x = fabs( r_x );
      96            8 :     r_y = fabs( r_y );
      97              : 
      98              :     /* see B.2.5, step 1 */
      99            8 :     if (( r_x < 0.000001 )||( r_y < 0.000001 ))
     100              :     {
     101              :         /* This is a valid case but cannot be handled by this function */
     102            0 :         result = U8_ERROR_EDGE_CASE_PARAM;
     103              :     }
     104              : 
     105            8 :     if ( result == U8_ERROR_NONE )
     106              :     {
     107              :         /* see B.2.4, step 1, eq 5.1 */
     108            8 :         const double cos_phi = cos( phi );
     109            8 :         const double sin_phi = sin( phi );
     110            8 :         const double half_dx = ( start_x - end_x ) / 2.0;
     111            8 :         const double half_dy = ( start_y - end_y ) / 2.0;
     112            8 :         const double rot_half_dx = cos_phi * half_dx + sin_phi * half_dy;
     113            8 :         const double rot_half_dy = (-sin_phi) * half_dx + cos_phi * half_dy;
     114              : 
     115              :         /* see B.2.5, step 3, eq 6.2 */
     116            8 :         double sqr_r_x = r_x * r_x;
     117            8 :         double sqr_r_y = r_y * r_y;
     118            8 :         const double sqr_rot_half_dx = rot_half_dx * rot_half_dx;
     119            8 :         const double sqr_rot_half_dy = rot_half_dy * rot_half_dy;
     120            8 :         const double sqr_too_small_factor = ( sqr_rot_half_dx / sqr_r_x ) + ( sqr_rot_half_dy / sqr_r_y );
     121              : 
     122              :         /* see B.2.5, step 3, eq 6.3 */
     123            8 :         if ( sqr_too_small_factor > 1.0 )
     124              :         {
     125            0 :             const double too_small_factor = sqrt( sqr_too_small_factor );
     126            0 :             r_x = too_small_factor * r_x;
     127            0 :             r_y = too_small_factor * r_y;
     128            0 :             sqr_r_x = r_x * r_x;
     129            0 :             sqr_r_y = r_y * r_y;
     130              :         }
     131              : 
     132              :         /* see B.2.4, step 2, eq 5.2 */
     133            8 :         const double numerator = ( sqr_r_x * sqr_r_y ) - ( sqr_r_x * sqr_rot_half_dy ) - ( sqr_r_y * sqr_rot_half_dx );
     134            8 :         double denominator = ( sqr_r_x * sqr_rot_half_dy ) + ( sqr_r_y * sqr_rot_half_dx );
     135            8 :         if ( denominator < 0.000000000001 )
     136              :         {
     137              :             /* start and end points are equal */
     138            0 :             result = U8_ERROR_VALUE_OUT_OF_RANGE;
     139            0 :             denominator = 0.000000000001;
     140              :         }
     141            8 :         const double sqr_factor = numerator / denominator;
     142            8 :         double rot_c_x = ( r_x * rot_half_dy ) / r_y;
     143            8 :         double rot_c_y = - ( r_y * rot_half_dx ) / r_x;
     144            8 :         if ( sqr_factor <= 0.0 )
     145              :         {
     146              :             /* case: rounding error and/or just 1 solution; factor is 0.0 */
     147            0 :             rot_c_x = 0.0;
     148            0 :             rot_c_y = 0.0;
     149              :         }
     150              :         else
     151              :         {
     152            8 :             const double factor = sqrt( sqr_factor );
     153            8 :             if ( large_arc != sweep_positive_dir )
     154              :             {
     155            7 :                 rot_c_x = factor * rot_c_x;
     156            7 :                 rot_c_y = factor * rot_c_y;
     157              :             }
     158              :             else
     159              :             {
     160            1 :                 rot_c_x = ( -factor ) * rot_c_x;
     161            1 :                 rot_c_y = ( -factor ) * rot_c_y;
     162              :             }
     163              :         }
     164              : 
     165              :         /* see B.2.4, step 3, eq 5.3 */
     166            8 :         const double half_way_x = ( start_x + end_x ) / 2.0;
     167            8 :         const double half_way_y = ( start_y + end_y ) / 2.0;
     168            8 :         *out_center_x = (( cos_phi * rot_c_x ) + ( (-sin_phi) * rot_c_y )) + half_way_x;
     169            8 :         *out_center_y = (( sin_phi * rot_c_x ) + ( cos_phi * rot_c_y )) + half_way_y;
     170              : 
     171              :         /* see B.2.4, step 4, eq 5.5 */
     172           16 :         *out_start_angle = draw_svg_path_data_private_get_angle( this_,
     173              :                                                                  1.0,
     174              :                                                                  0.0,
     175            8 :                                                                  ( rot_half_dx - rot_c_x ) / r_x,
     176            8 :                                                                  ( rot_half_dy - rot_c_y ) / r_y
     177              :                                                                );
     178              :         /* see B.2.4, step 4, eq 5.6 */
     179            8 :         const double delta_angle = draw_svg_path_data_private_get_angle( this_,
     180            8 :                                                                          ( rot_half_dx - rot_c_x ) / r_x,
     181            8 :                                                                          ( rot_half_dy - rot_c_y ) / r_y,
     182            8 :                                                                          ( (-rot_half_dx) - rot_c_x ) / r_x,
     183            8 :                                                                          ( (-rot_half_dy) - rot_c_y ) / r_y
     184              :                                                                        );
     185              :         *out_delta_angle
     186            8 :             = sweep_positive_dir
     187            3 :             ? ( ( delta_angle < 0.0 ) ? ( delta_angle + ( 2.0 * M_PI ) ) : delta_angle )
     188           11 :             : ( ( delta_angle > 0.0 ) ? ( delta_angle - ( 2.0 * M_PI ) ) : delta_angle );
     189              :     }
     190              : 
     191            8 :     U8_TRACE_END_ERR(result);
     192            8 :     return U8_ERROR_NONE;
     193              : }
     194              : 
     195              : 
     196              : /*
     197              : Copyright 2023-2025 Andreas Warnke
     198              : 
     199              : Licensed under the Apache License, Version 2.0 (the "License");
     200              : you may not use this file except in compliance with the License.
     201              : You may obtain a copy of the License at
     202              : 
     203              :     http://www.apache.org/licenses/LICENSE-2.0
     204              : 
     205              : Unless required by applicable law or agreed to in writing, software
     206              : distributed under the License is distributed on an "AS IS" BASIS,
     207              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     208              : See the License for the specific language governing permissions and
     209              : limitations under the License.
     210              : */
        

Generated by: LCOV version 2.0-1