Graphics-Penplotter-GcodeXY

 view release on metacpan or  search on metacpan

t/16-ana.t  view on Meta::CPAN


    # 8. t1 is slightly negative but t2 is positive => returns t2
    # E=(0.5, 0, 0), D=(1,0,0): t1 = -(0.5+1)/1=-1.5 (neg), t2=0.5 (pos)
    my $t7 = ana('_ana_ray_cylinder', 0.5,0,0, 1,0,0, 0,0, 1);
    ok defined $t7,                         'ray_cylinder: exits cylinder when inside on axis';
    ok abs($t7 - 0.5) < 1e-9,              'ray_cylinder: exit t=0.5 for inside shot';
}

# ==========================================================================
# SECTION 2: _ana_reflect
# ==========================================================================
{
    # 1. Normal incidence on x+ face: D=(-1,0,0), N=(1,0,0) => reflect=(1,0,0)
    my ($rx, $ry, $rz) = ana('_ana_reflect', -1,0,0, 1,0,0);
    ok abs($rx - 1.0) < 1e-9,              'reflect: normal incidence rx=1';
    ok abs($ry - 0.0) < 1e-9,              'reflect: normal incidence ry=0';
    ok abs($rz - 0.0) < 1e-9,              'reflect: normal incidence rz=0';

    # 2. Tangent ray unchanged: D=(0,1,0), N=(1,0,0) => D.N=0, reflect=(0,1,0)
    my ($rx2,$ry2,$rz2) = ana('_ana_reflect', 0,1,0, 1,0,0);
    ok abs($rx2 - 0.0) < 1e-9,             'reflect: tangent ray unchanged x';
    ok abs($ry2 - 1.0) < 1e-9,             'reflect: tangent ray unchanged y';

    # 3. 45-degree incidence: D=(-1,-1,0)/sqrt2, N=(1,0,0)
    # D.N = -1/sqrt2; reflect = D - 2*(-1/sqrt2)*(1,0,0) = D + (sqrt2,0,0)
    # = (-1/sqrt2 + sqrt2, -1/sqrt2, 0) = (1/sqrt2, -1/sqrt2, 0)
    my $s2 = 1.0/sqrt(2);
    my ($rx3,$ry3,$rz3) = ana('_ana_reflect', -$s2,-$s2,0, 1,0,0);
    ok abs($rx3 - $s2) < 1e-9,             'reflect: 45-degree rx=1/sqrt2';
    ok abs($ry3 - (-$s2)) < 1e-9,          'reflect: 45-degree ry=-1/sqrt2';
    ok abs($rz3 - 0.0) < 1e-9,             'reflect: 45-degree rz=0';

    # 4. Reflected vector has unit length
    my $len = sqrt($rx3**2 + $ry3**2 + $rz3**2);
    ok abs($len - 1.0) < 1e-9,             'reflect: output is unit length';

    # 5. 3-D case: D=(-1,0,-1)/sqrt2 (pointing down and inward), N=(1,0,0)
    # D.N = -1/sqrt2; reflect = (-1/sqrt2+sqrt2, 0, -1/sqrt2) = (1/sqrt2,0,-1/sqrt2)
    my ($rx4,$ry4,$rz4) = ana('_ana_reflect', -$s2,0,-$s2, 1,0,0);
    ok abs($rx4 - $s2) < 1e-9,             'reflect: 3-D case rx=1/sqrt2';
    ok abs($rz4 - (-$s2)) < 1e-9,          'reflect: 3-D case rz=-1/sqrt2 (still going down)';
}

# ==========================================================================
# SECTION 3: _ana_build_config
# ==========================================================================
{
    # Default observer: obs_angle=0, obs_dist=5*R, obs_height=5*R
    my %cfg = ana('_ana_build_config', 0,0, 1);

    ok abs($cfg{ex} - 5.0) < 1e-9,         'build_config: default ex=5';
    ok abs($cfg{ey} - 0.0) < 1e-9,         'build_config: default ey=0';
    ok abs($cfg{ez} - 5.0) < 1e-9,         'build_config: default ez=5';

    # phi_fwd should point from (5,0) toward (0,0): that is angle pi
    ok abs($cfg{phi_fwd} - $PI) < 1e-9,    'build_config: phi_fwd=pi for default obs';

    # ang_rad: 2*asin(1/5)*0.9 ~ 2*0.20136*0.9 ~ 0.36245
    my $expected_ang = 2.0 * atan2(0.2, sqrt(1-0.04)) * 0.90;
    ok abs($cfg{ang_rad} - $expected_ang) < 1e-6,
                                            'build_config: default ang_rad matches formula';

    # beta0 = atan2(H, D) = atan2(5,5) = pi/4
    ok abs($cfg{beta0} - $PI/4) < 1e-9,    'build_config: beta0=pi/4 for H=D';

    # elev_rad = beta0 * 0.8
    ok abs($cfg{elev_rad} - $PI/4 * 0.8) < 1e-9,
                                            'build_config: elev_rad=beta0*0.8';

    # Custom obs_angle=90 (observer from +y direction)
    my %cfg2 = ana('_ana_build_config', 0,0, 1, obs_angle => 90);
    ok abs($cfg2{ex} - 0.0) < 1e-6,        'build_config: obs_angle=90 ex~0';
    ok abs($cfg2{ey} - 5.0) < 1e-6,        'build_config: obs_angle=90 ey=5';
    # phi_fwd from (0,5) toward (0,0) = -pi/2
    ok abs($cfg2{phi_fwd} - (-$PI/2)) < 1e-6,
                                            'build_config: phi_fwd=-pi/2 for obs_angle=90';

    # Custom obs_dist
    my %cfg3 = ana('_ana_build_config', 0,0, 1, obs_dist => 10);
    ok abs($cfg3{ex} - 10.0) < 1e-9,       'build_config: custom obs_dist=10';

    # Non-origin cylinder centre
    my %cfg4 = ana('_ana_build_config', 3,4, 2);
    ok abs($cfg4{ex} - (3 + 10*cos(0))) < 1e-9,
                                            'build_config: shifted cylinder ex=cx+obs_dist';
    ok abs($cfg4{ey} - 4.0) < 1e-9,        'build_config: shifted cylinder ey=cy';

    # Custom angle_range and elev_range in degrees
    my %cfg5 = ana('_ana_build_config', 0,0, 1,
                   angle_range => 20, elev_range => 30);
    ok abs($cfg5{ang_rad}  - 20*$PI/180) < 1e-9, 'build_config: custom angle_range=20 deg';
    ok abs($cfg5{elev_rad} - 30*$PI/180) < 1e-9, 'build_config: custom elev_range=30 deg';

    # Croak when obs_dist <= R
    eval { ana('_ana_build_config', 0,0, 5, obs_dist => 5) };
    like $@, qr/obs_dist/i,                'build_config: croaks when obs_dist==R';

    eval { ana('_ana_build_config', 0,0, 5, obs_dist => 3) };
    like $@, qr/obs_dist/i,                'build_config: croaks when obs_dist<R';

    # Croak for R<=0
    eval { ana('_ana_build_config', 0,0, 0) };
    like $@, qr/radius/i,                  'build_config: croaks for R=0';
}

# ==========================================================================
# SECTION 4: _ana_transform_point
# ==========================================================================
# Use a fixed, analytically verified configuration:
#   cylinder at origin, R=1, observer at (5,0,5), phi_fwd=pi
# Centre of image (s=0, t=0): looking at phi=pi, beta=pi/4
#   Ray from (5,0,5) in dir (-cos45,0,-cos45) = (-s2,0,-s2)
#   Cylinder hit at t=4*sqrt2: M=(1,0,1)
#   Normal at M = (1,0,0)
#   Reflected: (-s2,0,-s2) -> (s2,0,-s2)  [z unchanged for vertical cylinder]
#   Paper hit: t_paper = -1/(-s2) = sqrt2; P=(1+1,0,0) = (2,0)
{
    my %cfg = ana('_ana_build_config', 0,0, 1);

    # Image bounding box 0..100 x 0..100; centre maps to (s=0,t=0)
    my ($px, $py) = ana('_ana_transform_point',



( run in 0.801 second using v1.01-cache-2.11-cpan-483215c6ad5 )