Create dynamic column
Here is one idea:

select start_date, stop_date
     , max(case min15 when 0 then sample_value end) as part1
     , max(case min15 when 15 then sample_value end) as part2
     , max(case min15 when 30 then sample_value end) as part3
     , max(case min15 when 45 then sample_value end) as part4 
from (
     select start_date, stop_date, sample_value, min15
          , row_number() over (partition by min15 
                               order by sample_date desc) as rn
     from (
         select h.*, trunc(to_char (sample_date,'MI') / 15) * 15 as min15 
         from heats h
     ) T
) U
where rn = 1
group by start_date, stop_date;


In the innermost select, an attribute min15 is calculated. It is the 15 min period to which sample_date belongs

select h.*
     , trunc(to_char (sample_date,'MI') / 15) * 15 as min15 
from heats h


At the next level, we enumerate the rows within each 15 min period, starting with the last one:

     select start_date, stop_date, sample_value, min15
          , row_number() over (partition by min15 
                               order by sample_date desc) as rn
     from (
         ...
     )


At the outermost level, we filter out all but the last in each 15 min period (where rn = 1)

We also pivot out the last values to an individual column. Since we get null for all but one, we aggregate to a single row with max:

select start_date, stop_date
     , max(case min15 when 0 then sample_value end) as part1
     , max(case min15 when 15 then sample_value end) as part2
     , max(case min15 when 30 then sample_value end) as part3
     , max(case min15 when 45 then sample_value end) as part4 
from (
    ...
)
where rn = 1
group by start_date, stop_date;


I don't normally use Oracle, so I googled for how to determine which 15 min period a row belongs to. There are probably more elegant ways to do it, but it should give you a start.

Fiddle