<commit_before>#include "PrimeTower.h"

#include <limits>

#include "ExtruderTrain.h"
#include "sliceDataStorage.h"
#include "gcodeExport.h"
#include "LayerPlan.h"
#include "infill.h"
#include "PrintFeature.h"
#include "raft.h"

#define CIRCLE_RESOLUTION 32 //The number of vertices in each circle.

namespace cura 
{

PrimeTower::PrimeTower(const SliceDataStorage& storage)
: is_hollow(false)
, wipe_from_middle(false)
{
    enabled = storage.getSettingBoolean("prime_tower_enable")
           && storage.getSettingInMicrons("prime_tower_wall_thickness") > 10
           && storage.getSettingInMicrons("prime_tower_size") > 10;
}

void PrimeTower::generateGroundpoly(const SliceDataStorage& storage)
{
    if (!enabled)
    {
        return;
    }

    extruder_count = storage.meshgroup->getExtruderCount();

    int64_t prime_tower_wall_thickness = storage.getSettingInMicrons("prime_tower_wall_thickness");
    int64_t tower_size = storage.getSettingInMicrons("prime_tower_size");
    bool circular_prime_tower = storage.getSettingBoolean("prime_tower_circular");

    if (prime_tower_wall_thickness * 2 < tower_size)
    {
        is_hollow = true;
    }

    PolygonRef p = ground_poly.newPoly();
    int tower_distance = 0; 
    int x = storage.getSettingInMicrons("prime_tower_position_x"); // storage.model_max.x
    int y = storage.getSettingInMicrons("prime_tower_position_y"); // storage.model_max.y
    if (circular_prime_tower)
    {
        double_t tower_radius = tower_size / 2;
        for (unsigned int i = 0; i < CIRCLE_RESOLUTION; i++)
        {
            const double angle = (double)i / CIRCLE_RESOLUTION * 2 * M_PI; //In radians.
            p.add(Point(x - tower_radius + tower_distance + cos(angle) * tower_radius, y + tower_radius + tower_distance + sin(angle) * tower_radius));
        }
    }
    else {
        p.add(Point(x + tower_distance, y + tower_distance));
        p.add(Point(x + tower_distance, y + tower_distance + tower_size));
        p.add(Point(x + tower_distance - tower_size, y + tower_distance + tower_size));
        p.add(Point(x + tower_distance - tower_size, y + tower_distance));
    }
    middle = Point(x - tower_size / 2, y + tower_size / 2);

    ground_poly_first_layer = ground_poly;  // for the first layer, we always generate a non-hollow prime tower
    if (is_hollow)
    {
        ground_poly = ground_poly.difference(ground_poly.offset(-prime_tower_wall_thickness));
    }

    post_wipe_point = Point(x + tower_distance - tower_size / 2, y + tower_distance + tower_size / 2);
}

void PrimeTower::generatePaths(const SliceDataStorage& storage)
{
    enabled &= storage.max_print_height_second_to_last_extruder >= 0; //Maybe it turns out that we don't need a prime tower after all because there are no layer switches.
    if (enabled)
    {
        generatePaths_denseInfill(storage);
        generateWipeLocations(storage);
    }
}

void PrimeTower::generatePaths_denseInfill(const SliceDataStorage& storage)
{
    int n_patterns = 2; // alternating patterns between layers
    int infill_overlap = 60; // so that it can't be zero; EDIT: wtf?
    int extra_infill_shift = 0;

    int64_t z = 0; // (TODO) because the prime tower stores the paths for each extruder for once instead of generating each layer, we don't know the z position
    EFillMethod infill_method;
    if (storage.getSettingBoolean("prime_tower_circular"))
    {
        infill_method = EFillMethod::CONCENTRIC;
    }
    else{
        infill_method = EFillMethod::LINES;
    }

    for (int extruder = 0; extruder < extruder_count; extruder++)
    {
        int line_width = storage.meshgroup->getExtruderTrain(extruder)->getSettingInMicrons("prime_tower_line_width");
        patterns_per_extruder.emplace_back(n_patterns);
        std::vector<ExtrusionMoves>& patterns = patterns_per_extruder.back();
        patterns.resize(n_patterns);
        for (int pattern_idx = 0; pattern_idx < n_patterns; pattern_idx++)
        {
            patterns[pattern_idx].polygons = ground_poly.offset(-line_width / 2);
            Polygons& result_lines = patterns[pattern_idx].lines;
            int outline_offset = -line_width;
            int line_distance = line_width;
            double fill_angle = 45 + pattern_idx * 90;
            Polygons& result_polygons = patterns[pattern_idx].polygons; // should remain empty, since we generate lines pattern!
            constexpr bool zig_zaggify_infill = false;
            Infill infill_comp(infill_method, zig_zaggify_infill, ground_poly, outline_offset, line_width, line_distance, infill_overlap, fill_angle, z, extra_infill_shift);
            infill_comp.generate(result_polygons, result_lines);
        }
        int line_width_layer0 = line_width;
        if (storage.getSettingAsPlatformAdhesion("adhesion_type") != EPlatformAdhesion::RAFT)
        {
            line_width_layer0 *= storage.meshgroup->getExtruderTrain(extruder)->getSettingAsRatio("initial_layer_line_width_factor");
        }
        pattern_per_extruder_layer0.emplace_back();
        ExtrusionMoves& pattern = pattern_per_extruder_layer0.back();
        pattern.polygons = ground_poly_first_layer.offset(-line_width_layer0 / 2);
        int outline_offset = -line_width_layer0;
        int line_distance = line_width_layer0;
        double fill_angle = 45;
        constexpr bool zig_zaggify_infill = false;
        Infill infill_comp(infill_method, zig_zaggify_infill, ground_poly_first_layer, outline_offset, line_width_layer0, line_distance, infill_overlap, fill_angle, z, extra_infill_shift);
        infill_comp.generate(pattern.polygons, pattern.lines);
    }
}


void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const GCodeExport& gcode, const int prev_extruder, const int new_extruder) const
{
    if (!enabled)
    {
        return;
    }
    if (gcode_layer.getPrimeTowerIsPlanned())
    { // don't print the prime tower if it has been printed already<commit_msg>CURA-5124 Remove hollow of the circular prime tower and also the infill.<commit_after>#include "PrimeTower.h"

#include <limits>

#include "ExtruderTrain.h"
#include "sliceDataStorage.h"
#include "gcodeExport.h"
#include "LayerPlan.h"
#include "infill.h"
#include "PrintFeature.h"
#include "raft.h"

#define CIRCLE_RESOLUTION 32 //The number of vertices in each circle.

namespace cura 
{

PrimeTower::PrimeTower(const SliceDataStorage& storage)
: is_hollow(false)
, wipe_from_middle(false)
{
    enabled = storage.getSettingBoolean("prime_tower_enable")
           && storage.getSettingInMicrons("prime_tower_wall_thickness") > 10
           && storage.getSettingInMicrons("prime_tower_size") > 10;
}

void PrimeTower::generateGroundpoly(const SliceDataStorage& storage)
{
    if (!enabled)
    {
        return;
    }

    extruder_count = storage.meshgroup->getExtruderCount();

    int64_t prime_tower_wall_thickness = storage.getSettingInMicrons("prime_tower_wall_thickness");
    int64_t tower_size = storage.getSettingInMicrons("prime_tower_size");
    bool circular_prime_tower = storage.getSettingBoolean("prime_tower_circular");

    if (!circular_prime_tower && prime_tower_wall_thickness * 2 < tower_size)
    {
        is_hollow = true;
    }

    PolygonRef p = ground_poly.newPoly();
    int tower_distance = 0; 
    int x = storage.getSettingInMicrons("prime_tower_position_x"); // storage.model_max.x
    int y = storage.getSettingInMicrons("prime_tower_position_y"); // storage.model_max.y
    if (circular_prime_tower)
    {
        double_t tower_radius = tower_size / 2;
        for (unsigned int i = 0; i < CIRCLE_RESOLUTION; i++)
        {
            const double angle = (double)i / CIRCLE_RESOLUTION * 2 * M_PI; //In radians.
            p.add(Point(x - tower_radius + tower_distance + cos(angle) * tower_radius, y + tower_radius + tower_distance + sin(angle) * tower_radius));
        }
    }
    else {
        p.add(Point(x + tower_distance, y + tower_distance));
        p.add(Point(x + tower_distance, y + tower_distance + tower_size));
        p.add(Point(x + tower_distance - tower_size, y + tower_distance + tower_size));
        p.add(Point(x + tower_distance - tower_size, y + tower_distance));
    }
    middle = Point(x - tower_size / 2, y + tower_size / 2);

    ground_poly_first_layer = ground_poly;  // for the first layer, we always generate a non-hollow prime tower
    if (is_hollow)
    {
        ground_poly = ground_poly.difference(ground_poly.offset(-prime_tower_wall_thickness));
    }

    post_wipe_point = Point(x + tower_distance - tower_size / 2, y + tower_distance + tower_size / 2);
}

void PrimeTower::generatePaths(const SliceDataStorage& storage)
{
    enabled &= storage.max_print_height_second_to_last_extruder >= 0; //Maybe it turns out that we don't need a prime tower after all because there are no layer switches.
    if (enabled)
    {
        generatePaths_denseInfill(storage);
        generateWipeLocations(storage);
    }
}

void PrimeTower::generatePaths_denseInfill(const SliceDataStorage& storage)
{
    int n_patterns = 2; // alternating patterns between layers
    int infill_overlap = 60; // so that it can't be zero; EDIT: wtf?
    int extra_infill_shift = 0;

    int64_t z = 0; // (TODO) because the prime tower stores the paths for each extruder for once instead of generating each layer, we don't know the z position
    EFillMethod infill_method;
    EFillMethod first_layer_infill_method;
    if (storage.getSettingBoolean("prime_tower_circular"))
    {
        infill_method = EFillMethod::NONE;
        first_layer_infill_method = EFillMethod::CONCENTRIC;
    }
    else{
        infill_method = EFillMethod::LINES;
        first_layer_infill_method = EFillMethod::LINES;
    }

    for (int extruder = 0; extruder < extruder_count; extruder++)
    {
        int line_width = storage.meshgroup->getExtruderTrain(extruder)->getSettingInMicrons("prime_tower_line_width");
        patterns_per_extruder.emplace_back(n_patterns);
        std::vector<ExtrusionMoves>& patterns = patterns_per_extruder.back();
        patterns.resize(n_patterns);
        for (int pattern_idx = 0; pattern_idx < n_patterns; pattern_idx++)
        {
            patterns[pattern_idx].polygons = ground_poly.offset(-line_width / 2);
            Polygons& result_lines = patterns[pattern_idx].lines;
            int outline_offset = -line_width;
            int line_distance = line_width;
            double fill_angle = 45 + pattern_idx * 90;
            Polygons& result_polygons = patterns[pattern_idx].polygons; // should remain empty, since we generate lines pattern!
            constexpr bool zig_zaggify_infill = false;
            Infill infill_comp(infill_method, zig_zaggify_infill, ground_poly, outline_offset, line_width, line_distance, infill_overlap, fill_angle, z, extra_infill_shift);
            infill_comp.generate(result_polygons, result_lines);
        }
        int line_width_layer0 = line_width;
        if (storage.getSettingAsPlatformAdhesion("adhesion_type") != EPlatformAdhesion::RAFT)
        {
            line_width_layer0 *= storage.meshgroup->getExtruderTrain(extruder)->getSettingAsRatio("initial_layer_line_width_factor");
        }
        pattern_per_extruder_layer0.emplace_back();
        ExtrusionMoves& pattern = pattern_per_extruder_layer0.back();
        pattern.polygons = ground_poly_first_layer.offset(-line_width_layer0 / 2);
        int outline_offset = -line_width_layer0;
        int line_distance = line_width_layer0;
        double fill_angle = 45;
        constexpr bool zig_zaggify_infill = false;
        Infill infill_comp(first_layer_infill_method, zig_zaggify_infill, ground_poly_first_layer, outline_offset, line_width_layer0, line_distance, infill_overlap, fill_angle, z, extra_infill_shift);
        infill_comp.generate(pattern.polygons, pattern.lines);
    }
}


void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const GCodeExport& gcode, const int prev_extruder, const int new_extruder) const
{
    if (!enabled)
    {
        return;
    }
    if (gcode_layer.getPrimeTowerIsPlanned())
    { // don't print the prime tower if it has been printed already
{'fraction_non_alphanumeric': 0.09425287356321839, 'fraction_numerical': 0.0077175697865353035, 'mean_word_length': 3.607034795763994, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3782533', 'n_tokens_mistral': 4044, 'n_tokens_neox': 3875, 'n_words': 811}