| | #pragma once |
| |
|
| | #include "diffvg.h" |
| | #include "atomic.h" |
| |
|
| | enum class FilterType { |
| | Box, |
| | Tent, |
| | RadialParabolic, |
| | Hann |
| | }; |
| |
|
| | struct Filter { |
| | FilterType type; |
| | float radius; |
| | }; |
| |
|
| | struct DFilter { |
| | float radius; |
| | }; |
| |
|
| | DEVICE |
| | inline |
| | float compute_filter_weight(const Filter &filter, |
| | float dx, |
| | float dy) { |
| | if (fabs(dx) > filter.radius || fabs(dy) > filter.radius) { |
| | return 0; |
| | } |
| | if (filter.type == FilterType::Box) { |
| | return 1.f / square(2 * filter.radius); |
| | } else if (filter.type == FilterType::Tent) { |
| | return (filter.radius - fabs(dx)) * (filter.radius - fabs(dy)) / |
| | square(square(filter.radius)); |
| | } else if (filter.type == FilterType::RadialParabolic) { |
| | return (4.f / 3.f) * (1 - square(dx / filter.radius)) * |
| | (4.f / 3.f) * (1 - square(dy / filter.radius)); |
| | } else { |
| | assert(filter.type == FilterType::Hann); |
| | |
| | auto ndx = (dx / (2*filter.radius)) + 0.5f; |
| | auto ndy = (dy / (2*filter.radius)) + 0.5f; |
| | |
| | return 0.5f * (1.f - cos(float(2 * M_PI) * ndx)) * |
| | 0.5f * (1.f - cos(float(2 * M_PI) * ndy)) / |
| | square(filter.radius); |
| | } |
| | } |
| |
|
| | DEVICE |
| | inline |
| | void d_compute_filter_weight(const Filter &filter, |
| | float dx, |
| | float dy, |
| | float d_return, |
| | DFilter *d_filter) { |
| | if (filter.type == FilterType::Box) { |
| | |
| | atomic_add(d_filter->radius, |
| | d_return * (-2) * 2 * filter.radius / cubic(2 * filter.radius)); |
| | } else if (filter.type == FilterType::Tent) { |
| | |
| | |
| | auto fx = filter.radius - fabs(dx); |
| | auto fy = filter.radius - fabs(dy); |
| | auto norm = 1 / square(filter.radius); |
| | auto d_fx = d_return * fy * norm; |
| | auto d_fy = d_return * fx * norm; |
| | auto d_norm = d_return * fx * fy; |
| | atomic_add(d_filter->radius, |
| | d_fx + d_fy + (-4) * d_norm / pow(filter.radius, 5)); |
| | } else if (filter.type == FilterType::RadialParabolic) { |
| | |
| | |
| | |
| | |
| | auto r3 = filter.radius * filter.radius * filter.radius; |
| | auto d_radius = -(2 * square(dx) + 2 * square(dy)) / r3; |
| | atomic_add(d_filter->radius, d_radius); |
| | } else { |
| | assert(filter.type == FilterType::Hann); |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | auto ndx = (dx / (2*filter.radius)) + 0.5f; |
| | auto ndy = (dy / (2*filter.radius)) + 0.5f; |
| | auto fx = 0.5f * (1.f - cos(float(2*M_PI) * ndx)); |
| | auto fy = 0.5f * (1.f - cos(float(2*M_PI) * ndy)); |
| | auto norm = 1 / square(filter.radius); |
| | auto d_fx = d_return * fy * norm; |
| | auto d_fy = d_return * fx * norm; |
| | auto d_norm = d_return * fx * fy; |
| | auto d_ndx = d_fx * 0.5f * sin(float(2*M_PI) * ndx) * float(2*M_PI); |
| | auto d_ndy = d_fy * 0.5f * sin(float(2*M_PI) * ndy) * float(2*M_PI); |
| | atomic_add(d_filter->radius, |
| | d_ndx * (-2*dx / square(2*filter.radius)) + |
| | d_ndy * (-2*dy / square(2*filter.radius)) + |
| | (-2) * d_norm / cubic(filter.radius)); |
| | } |
| | } |
| |
|