LCOV - code coverage report
Current view: top level - pencil/source/draw - draw_svg_path_data.inl (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.61.0_covts Lines: 68 82 82.9 %
Date: 2024-10-26 21:44:38 Functions: 5 6 83.3 %

          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-2024 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 1.16