BachiLi / diffvg

Differentiable Vector Graphics Rasterization
https://people.csail.mit.edu/tzumao/diffvg/
Apache License 2.0
902 stars 152 forks source link

Square linecaps? #70

Open tristanryerparke opened 9 months ago

tristanryerparke commented 9 months ago

Is it possible to specify a stroke-linecap property for a pydiffvg.path ? If not then this would be a feature request for 'round' (currently implemented and default), 'flat' and 'butt'. Thanks, Tristan

tristanryerparke commented 9 months ago

Update: I did some digging in the code and tried to remove the round line caps sampling in sample_boundary.h by commenting out these lines:

 if (stroke_perturb_direction != 0.f && !path.is_closed) {
        // We need to samples the "caps" of the path
        // length of a cap is pi * abs(stroke_perturb_direction)
        // there are two caps
        if (path.num_control_points[sample_id] != 1) {
            auto cap_length = 0.f;
            if (path.thickness != nullptr) {
                auto r0 = path.thickness[0];
                auto r1 = path.thickness[path.num_points - 1];
                cap_length = float(M_PI) * (r0 + r1);
            } else {
                cap_length = 2 * float(M_PI) * stroke_radius;
            }
            auto cap_prob = cap_length / (cap_length + path_length);
            if (t < cap_prob) {
                t = t / cap_prob;
                pdf *= cap_prob;
                auto r0 = stroke_radius;
                auto r1 = stroke_radius;
                if (path.thickness != nullptr) {
                    r0 = path.thickness[0];
                    r1 = path.thickness[path.num_points - 1];
                }
                // HACK: in theory we want to compute the tangent and
                //       sample the hemi-circle, but here we just sample the
                //       full circle since it's less typing
                if (stroke_perturb_direction < 0) {
                    // Sample the cap at the beginning
                    auto p0 = Vector2f{path.points[0], path.points[1]};
                    auto offset = Vector2f{
                        r0 * cos(2 * float(M_PI) * t),
                        r0 * sin(2 * float(M_PI) * t)
                    };
                    normal = normalize(offset);
                    pdf /= (2 * float(M_PI) * r0);
                    data.path.base_point_id = 0;
                    data.path.point_id = 0;
                    data.path.t = 0;
                    return p0 + offset;
                } else {
                    // Sample the cap at the end
                    auto p0 = Vector2f{path.points[2 * (path.num_points - 1)],
                                       path.points[2 * (path.num_points - 1) + 1]};
                    auto offset = Vector2f{
                        r1 * cos(2 * float(M_PI) * t),
                        r1 * sin(2 * float(M_PI) * t)
                    };
                    normal = normalize(offset);
                    pdf /= (2 * float(M_PI) * r1);
                    data.path.base_point_id = path.num_base_points - 1;
                    data.path.point_id = path.num_points - 2 - 
                                         path.num_control_points[data.path.base_point_id];
                    data.path.t = 1;
                    return p0 + offset;
                }
            } else {
                t = (t - cap_prob) / (1 - cap_prob);
                pdf *= (1 - cap_prob);
            }
        }
    }

However upon build and install of the library the round line caps are still rendered. I tried introducing print statements to see if the code in sample_boundary.h was actually being called by my script and it is. Any ideas on how to proceed? Thanks