<commit_before>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "PrimeTower.h"

#include <algorithm>
#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)
: wipe_from_middle(false)
{
    enabled = storage.getSettingBoolean("prime_tower_enable")
           && storage.getSettingInMicrons("prime_tower_wall_thickness") > 10
           && storage.getSettingInMicrons("prime_tower_size") > 10;

    extruder_count = storage.meshgroup->getExtruderCount();
    extruder_order.resize(extruder_count);
    for (unsigned int extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++)
    {
        extruder_order[extruder_nr] = extruder_nr; //Start with default order, then sort.
    }
    //Sort from high adhesion to low adhesion.
    const SliceDataStorage* storage_ptr = &storage; //Communicate to lambda via pointer to prevent copy.
    std::sort(extruder_order.begin(), extruder_order.end(), [storage_ptr](const unsigned int& extruder_nr_a, const unsigned int& extruder_nr_b) -> bool
    {
        const double adhesion_a = storage_ptr->meshgroup->getExtruderTrain(extruder_nr_a)->getSettingAsRatio("material_adhesion_tendency");
        const double adhesion_b = storage_ptr->meshgroup->getExtruderTrain(extruder_nr_b)->getSettingAsRatio("material_adhesion_tendency");
        return adhesion_a < adhesion_b;
    });
}

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

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

    PolygonRef p = outer_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);

    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);
    }
}

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

    coord_t cumulative_inset = 0; //Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder.
    coord_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 first_layer_infill_method;
    for (unsigned int extruder = 0; extruder < extruder_count; extruder++)
    {
        const coord_t line_width = storage.meshgroup->getExtruderTrain(extruder)->getSettingInMicrons("prime_tower_line_width");
        const coord_t wall_thickness = storage.meshgroup->getExtruderTrain(extruder)->getSettingInMicrons("prime_tower_wall_thickness");
        patterns_per_extruder.emplace_back(n_patterns);
        std::vector<ExtrusionMoves>& patterns = patterns_per_extruder.back();
        patterns.resize(n_patterns);

        // If the prime tower is circular, instead of creating a concentric infill in the normal layers, the tower is
        // built as walls, in order to keep always the same direction while printing
        if (storage.getSettingBoolean("prime_tower_circular"))
        {
            first_layer_infill_method = EFillMethod::CONCENTRIC;
            const int walls = std::ceil(wall_thickness / line_width);
            for (int wall_nr = 0; wall_nr < walls; wall_nr++)
            {
                // Create a new polygon with an offset from the outer polygon. The polygon is copied in the n_patterns,
                // since printing walls will be the same in each layer.
                Polygons polygons = outer_poly.offset(-cumulative_inset - wall_nr * line_width - line_width / 2);
                for (int pattern_idx = 0; pattern_idx < n_patterns; pattern_idx++)
                {
                    patterns[pattern_idx].polygons.add(polygons);
                }
            }
            cumulative_inset += walls * line_width;
        }
        else
        {
            first_layer_infill_method = EFillMethod::LINES;
            for (int pattern_idx = 0; pattern_idx < n_patterns; pattern_idx++)
            {
                Polygons polygons = outer_poly.offset(-cumulative_inset - line_width / 2);
                if ((wall_thickness + cumulative_inset) * 2 < tower_size)
                {
                    polygons = polygons.difference(polygons.offset(-wall_thickness));
                }
                patterns[pattern_idx].polygons = polygons;
                Polygons& result_lines = patterns[pattern_idx].lines;
                const coord_t outline_offset = -line_width / 2;
                const coord_t line_distance = line_width;
                const 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(EFillMethod::LINES, zig_zaggify_infill, polygons, outline_offset, line_width,
                                   line_distance, infill_overlap, fill_angle, z, extra_infill_shift);
                infill_comp.generate(result_polygons, result_lines);
            }
            cumulative_inset += wall_thickness;
        }
        coord_t 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 = outer_poly.offset(-line_width_layer0 / 2);
        const coord_t outline_offset = -line_width_layer0;
        const coord_t line_distance = line_width_layer0;
        constexpr double fill_angle = 45;
        constexpr bool zig_zaggify_infill = false;
        Infill infill_comp(first_layer_infill_method, zig_zaggify_infill, outer_poly, 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(new_extruder))
    { // don't print the prime tower if it has been printed already with this extruder.
        return;
    }

    if (gcode_layer.getLayerNr() > storage.max_print_height_second_to_last_extruder + 1)
    {
        return;
    }

    bool post_wipe = storage.meshgroup->getExtruderTrain(prev_extruder)->getSettingBoolean("prime_tower_wipe_enabled");

    // Do not wipe on the first layer, we will generate non-hollow prime tower there for better bed adhesion.
    const int layer_nr = gcode_layer.getLayerNr();
    if (prev_extruder == new_extruder || layer_nr == 0)
    {
        post_wipe = false;
    }

    addToGcode_denseInfill(storage, gcode_layer, new_extruder);

    // post-wipe:
    if (post_wipe)
    { //Make sure we wipe the old extruder on the prime tower.
        gcode_layer.addTravel(post_wipe_point - gcode.getExtruderOffset(prev_extruder) + gcode.getExtruderOffset(new_extruder));
    }

    gcode_layer.setPrimeTowerIsPlanned(new_extruder);
}

void PrimeTower::addToGcode_denseInfill(const SliceDataStorage& storage, LayerPlan& gcode_layer, const int extruder_nr) const
{
    const ExtrusionMoves& pattern = (gcode_layer.getLayerNr() == -Raft::getFillerLayerCount(storage))
        ? pattern_per_extruder_layer0[extruder_nr]
        : patterns_per_extruder[extruder_nr][((gcode_layer.getLayerNr() % 2) + 2) % 2]; // +2) %2 to handle negative layer numbers

    const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr];

    gcode_layer.addPolygonsByOptimizer(pattern.polygons, config);
    gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines);
}

Point PrimeTower::getLocationBeforePrimeTower(const SliceDataStorage& storage) const
{
    Point ret(0, 0);
    int absolute_starting_points = 0;
    for (int extruder_nr = 0; extruder_nr < storage.meshgroup->getExtruderCount(); extruder_nr++)
    {
        ExtruderTrain& train = *storage.meshgroup->getExtruderTrain(0);
        if (train.getSettingBoolean("machine_extruder_start_pos_abs"))
        {
            ret += Point(train.getSettingInMicrons("machine_extruder_start_pos_x"), train.getSettingInMicrons("machine_extruder_start_pos_y"));
            absolute_starting_points++;
        }
    }
    if (absolute_starting_points > 0)
    { // take the average over all absolute starting positions
        ret /= absolute_starting_points;
    }
    else
    { // use the middle of the bed
        ret = storage.machine_size.flatten().getMiddle();
    }
    return ret;
}

void PrimeTower::subtractFromSupport(SliceDataStorage& storage)
{
    const Polygons outside_polygon = outer_poly.getOutsidePolygons();
    AABB outside_polygon_boundary_box(outside_polygon);
    for(size_t layer = 0; layer <= (size_t)storage.max_print_height_second_to_last_extruder + 1 && layer < storage.support.supportLayers.size(); layer++)
    {
        SupportLayer& support_layer = storage.support.supportLayers[layer];
        // take the differences of the support infill parts and the prime tower area
        support_layer.excludeAreasFromSupportInfillAreas(outside_polygon, outside_polygon_boundary_box);
    }
}

}//namespace cura
<commit_msg>Print prime tower shells in the pre-determined order<commit_after>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "PrimeTower.h"

#include <algorithm>
#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)
: wipe_from_middle(false)
{
    enabled = storage.getSettingBoolean("prime_tower_enable")
           && storage.getSettingInMicrons("prime_tower_wall_thickness") > 10
           && storage.getSettingInMicrons("prime_tower_size") > 10;

    extruder_count = storage.meshgroup->getExtruderCount();
    extruder_order.resize(extruder_count);
    for (unsigned int extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++)
    {
        extruder_order[extruder_nr] = extruder_nr; //Start with default order, then sort.
    }
    //Sort from high adhesion to low adhesion.
    const SliceDataStorage* storage_ptr = &storage; //Communicate to lambda via pointer to prevent copy.
    std::sort(extruder_order.begin(), extruder_order.end(), [storage_ptr](const unsigned int& extruder_nr_a, const unsigned int& extruder_nr_b) -> bool
    {
        const double adhesion_a = storage_ptr->meshgroup->getExtruderTrain(extruder_nr_a)->getSettingAsRatio("material_adhesion_tendency");
        const double adhesion_b = storage_ptr->meshgroup->getExtruderTrain(extruder_nr_b)->getSettingAsRatio("material_adhesion_tendency");
        return adhesion_a < adhesion_b;
    });
}

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

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

    PolygonRef p = outer_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);

    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);
    }
}

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

    patterns_per_extruder.resize(extruder_order.size());
    coord_t cumulative_inset = 0; //Each tower shape is going to be printed inside the other. This is the inset we're doing for each extruder.
    coord_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 first_layer_infill_method;
    for (unsigned int extruder : extruder_order)
    {
        const coord_t line_width = storage.meshgroup->getExtruderTrain(extruder)->getSettingInMicrons("prime_tower_line_width");
        const coord_t wall_thickness = storage.meshgroup->getExtruderTrain(extruder)->getSettingInMicrons("prime_tower_wall_thickness");
        patterns_per_extruder[extruder] = std::vector<ExtrusionMoves>(n_patterns);
        std::vector<ExtrusionMoves>& patterns = patterns_per_extruder[extruder];
        patterns.resize(n_patterns);

        // If the prime tower is circular, instead of creating a concentric infill in the normal layers, the tower is
        // built as walls, in order to keep always the same direction while printing
        if (storage.getSettingBoolean("prime_tower_circular"))
        {
            first_layer_infill_method = EFillMethod::CONCENTRIC;
            const int walls = std::ceil(wall_thickness / line_width);
            for (int wall_nr = 0; wall_nr < walls; wall_nr++)
            {
                // Create a new polygon with an offset from the outer polygon. The polygon is copied in the n_patterns,
                // since printing walls will be the same in each layer.
                Polygons polygons = outer_poly.offset(-cumulative_inset - wall_nr * line_width - line_width / 2);
                for (int pattern_idx = 0; pattern_idx < n_patterns; pattern_idx++)
                {
                    patterns[pattern_idx].polygons.add(polygons);
                }
            }
            cumulative_inset += walls * line_width;
        }
        else
        {
            first_layer_infill_method = EFillMethod::LINES;
            for (int pattern_idx = 0; pattern_idx < n_patterns; pattern_idx++)
            {
                Polygons polygons = outer_poly.offset(-cumulative_inset - line_width / 2);
                if ((wall_thickness + cumulative_inset) * 2 < tower_size)
                {
                    polygons = polygons.difference(polygons.offset(-wall_thickness));
                }
                patterns[pattern_idx].polygons = polygons;
                Polygons& result_lines = patterns[pattern_idx].lines;
                const coord_t outline_offset = -line_width / 2;
                const coord_t line_distance = line_width;
                const 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(EFillMethod::LINES, zig_zaggify_infill, polygons, outline_offset, line_width,
                                   line_distance, infill_overlap, fill_angle, z, extra_infill_shift);
                infill_comp.generate(result_polygons, result_lines);
            }
            cumulative_inset += wall_thickness;
        }
        coord_t 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 = outer_poly.offset(-line_width_layer0 / 2);
        const coord_t outline_offset = -line_width_layer0;
        const coord_t line_distance = line_width_layer0;
        constexpr double fill_angle = 45;
        constexpr bool zig_zaggify_infill = false;
        Infill infill_comp(first_layer_infill_method, zig_zaggify_infill, outer_poly, 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(new_extruder))
    { // don't print the prime tower if it has been printed already with this extruder.
        return;
    }

    if (gcode_layer.getLayerNr() > storage.max_print_height_second_to_last_extruder + 1)
    {
        return;
    }

    bool post_wipe = storage.meshgroup->getExtruderTrain(prev_extruder)->getSettingBoolean("prime_tower_wipe_enabled");

    // Do not wipe on the first layer, we will generate non-hollow prime tower there for better bed adhesion.
    const int layer_nr = gcode_layer.getLayerNr();
    if (prev_extruder == new_extruder || layer_nr == 0)
    {
        post_wipe = false;
    }

    addToGcode_denseInfill(storage, gcode_layer, new_extruder);

    // post-wipe:
    if (post_wipe)
    { //Make sure we wipe the old extruder on the prime tower.
        gcode_layer.addTravel(post_wipe_point - gcode.getExtruderOffset(prev_extruder) + gcode.getExtruderOffset(new_extruder));
    }

    gcode_layer.setPrimeTowerIsPlanned(new_extruder);
}

void PrimeTower::addToGcode_denseInfill(const SliceDataStorage& storage, LayerPlan& gcode_layer, const int extruder_nr) const
{
    const ExtrusionMoves& pattern = (gcode_layer.getLayerNr() == -Raft::getFillerLayerCount(storage))
        ? pattern_per_extruder_layer0[extruder_nr]
        : patterns_per_extruder[extruder_nr][((gcode_layer.getLayerNr() % 2) + 2) % 2]; // +2) %2 to handle negative layer numbers

    const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr];

    gcode_layer.addPolygonsByOptimizer(pattern.polygons, config);
    gcode_layer.addLinesByOptimizer(pattern.lines, config, SpaceFillType::Lines);
}

Point PrimeTower::getLocationBeforePrimeTower(const SliceDataStorage& storage) const
{
    Point ret(0, 0);
    int absolute_starting_points = 0;
    for (int extruder_nr = 0; extruder_nr < storage.meshgroup->getExtruderCount(); extruder_nr++)
    {
        ExtruderTrain& train = *storage.meshgroup->getExtruderTrain(0);
        if (train.getSettingBoolean("machine_extruder_start_pos_abs"))
        {
            ret += Point(train.getSettingInMicrons("machine_extruder_start_pos_x"), train.getSettingInMicrons("machine_extruder_start_pos_y"));
            absolute_starting_points++;
        }
    }
    if (absolute_starting_points > 0)
    { // take the average over all absolute starting positions
        ret /= absolute_starting_points;
    }
    else
    { // use the middle of the bed
        ret = storage.machine_size.flatten().getMiddle();
    }
    return ret;
}

void PrimeTower::subtractFromSupport(SliceDataStorage& storage)
{
    const Polygons outside_polygon = outer_poly.getOutsidePolygons();
    AABB outside_polygon_boundary_box(outside_polygon);
    for(size_t layer = 0; layer <= (size_t)storage.max_print_height_second_to_last_extruder + 1 && layer < storage.support.supportLayers.size(); layer++)
    {
        SupportLayer& support_layer = storage.support.supportLayers[layer];
        // take the differences of the support infill parts and the prime tower area
        support_layer.excludeAreasFromSupportInfillAreas(outside_polygon, outside_polygon_boundary_box);
    }
}

}//namespace cura
<|endoftext|>


<commit_before>
// License: BSD 3-clause
// Copyright: Nick Porcino, 2017

#include "Screenplay.h"
#include <LabText/TextScanner.h>
#include <LabText/TextScanner.hpp>

namespace lab
{
	using namespace std;
	using namespace TextScanner;

	std::string ScriptNode::as_string() const
	{
		switch (kind)
		{
		case NodeKind::KeyValue: return key + ": " + content;
		case NodeKind::Divider: return content + "\n";
		case NodeKind::Character:
		case NodeKind::Location: return content + "\n";
		case NodeKind::Action: return content + "\n";
		case NodeKind::Dialog: return key + "\n" + content;
		case NodeKind::Direction: return content + "\n";
		case NodeKind::Transition: return ToUpper(content) + "\n";
			break;
		}

		return "";
	}

	Sequence::Sequence(const std::string & name_, bool interior, bool exterior)
		: interior(interior), exterior(exterior)
	{
		name = TextScanner::StripLeadingWhitespace(name_);
	}

	Sequence::Sequence(Sequence && rh)
		: name(rh.name), interior(rh.interior), exterior(rh.exterior)
	{
		nodes.swap(rh.nodes);
	}

	Sequence & Sequence::operator=(Sequence && rh)
	{
		interior = rh.interior;
		exterior = rh.exterior;
		name = rh.name;
		nodes.swap(rh.nodes);
		return *this;
	}

	std::string Sequence::as_string() const
	{
		std::string res;
		if (interior && exterior)
			res = "INT/EXT ";
		else if (interior)
			res = "INT. ";
		else if (exterior)
			res = "EXT. ";
		return res + name;
	}

	Script::Script(Script && rh) noexcept
		: title(std::move(rh.title))
		, characters(std::move(rh.characters))
		, sets(std::move(rh.sets))
		, sequences(std::move(rh.sequences))
	{
	}

#ifdef _MSC_VER
	inline FILE* open_file(const filesystem::path& p)
	{
		return _wfopen(p.c_str(), L"r");
	}
#else
	inline FILE* open_file(const filesystem::path& p)
	{
		return std::fopen(p.c_str(), "r");
	}
#endif

	bool isLineContinuation(const string & s)
	{
		if (s.length() < 1)
			return false;
		return s[0] == '\t' || (s[0] == ' ');
	}

	string parseValue(const string & s, const vector<string> & lines, size_t & i)
	{
		string result;
		size_t off = s.find(':');
		if (off != string::npos)
			result = s.substr(off);

		size_t line = i + 1;
		while (isLineContinuation(lines[line])) {
			result += lines[line];
			++line;
		}
		i = line - 1;
		return StripLeadingWhitespace(result);
	}

	bool lineIsUpperCase(const char * curr, const char * end)
	{
		const char * next = tsScanForBeginningOfNextLine(curr, end);
		while (next > curr) {
			if (*curr >= 'a' && *curr <= 'z')
				return false;
			++curr;
		}
		return true;
	}

	bool charIsEmphasis(char c) {
		return c == '*' || c == '_';
	}

#ifdef _MSC_VER
#define strnicmp _strnicmp
#endif

	bool beginsWith(const std::string& input, const char * match)
	{
		return !strnicmp(input.c_str(), match, (strlen(match)));
	}

	string parseShot(const std::string & input, bool & interior, bool & exterior)
	{
		interior = false;
		exterior = false;

		if (input.length() < 2)
			return "";

		if (input[0] == '.')
			return StripLeadingWhitespace(input.substr(1));

		if (beginsWith(input, "INT./EXT.") || beginsWith(input, "EXT./INT.")) {
			interior = true;
			exterior = true;
			return StripLeadingWhitespace(input.substr(9));
		}

		if (beginsWith(input, "INT./EXT") || beginsWith(input, "EXT./INT")) {
			interior = true;
			exterior = true;
			return StripLeadingWhitespace(input.substr(8));
		}

		if (beginsWith(input, "INT/EXT") || beginsWith(input, "EXT/INT")) {
			interior = true;
			exterior = true;
			return StripLeadingWhitespace(input.substr(7));
		}

		if (beginsWith(input, "INT ") || beginsWith(input, "EXT ") || beginsWith(input, "INT.") || beginsWith(input, "EXT.") || beginsWith(input, "I/E "))
		{
			interior = beginsWith(input, "I");
			exterior = beginsWith(input, "E") || beginsWith(input, "I/E ");
			return StripLeadingWhitespace(input.substr(4));
		}
		return "";
	}

	bool isShot(const std::string& input)
	{
		if (input.length() < 2)
			return false;

		if (input[0] == '.' && input[1] != '.')
			return true;

		return beginsWith(input, "INT ") || beginsWith(input, "EXT ")
			|| beginsWith(input, "INT.") || beginsWith(input, "EXT.")
			|| beginsWith(input, "INT/EXT") || beginsWith(input, "EXT/INT")
			|| beginsWith(input, "I/E ");
	}

	bool isTransition(const std::string & input)
	{
		if (!input.length())
			return false;

		string s = StripLeadingWhitespace(input);
		size_t len = s.length() - 1;
		if (len < 4)
			return false;

		if (s[0] == '>')
			return true;

		if (!lineIsUpperCase(input.c_str(), input.c_str() + input.length()))
			return false;

		const char * transitions[] = {
			"CUT TO BLACK",
			"cut to:",
			"CUT TO:",
			"INTERCUT WITH:",
			"FADE IN:",
			"TITLE OVER:",
			"SPLIT SCREEN:",
			"OPENING CREDITS",
			"END CREDITS"
		};

		for (auto str : transitions)
			if (s.find(str) != string::npos)
				return true;

		string end = s.substr(len - 3, len - 2);
		return beginsWith(end, " TO") || beginsWith(end, " IN");
	}

	string parseTransition(const std::string & input)
	{
		string r = StripLeadingWhitespace(input);
		if (r[0] == '>')
			r = r.substr(1);

		return StripTrailingWhitespace(StripLeadingWhitespace(r));
	}

	bool isDialog(const std::string & input)
	{
		if (input.length() < 2)
			return false;

		if (input[0] == '@')
			return true;

		if (isTransition(input))
			return false;

		return lineIsUpperCase(input.c_str(), input.c_str() + input.length());
	}

	string parseDialog(const string& s, string& character, const vector<string>& lines, size_t & i)
	{
		if (s[0] == '@')
			character = s.substr(1);
		else
			character = s;

		string result;

		size_t line = i + 1;
		while (line < lines.size() && lines[line].length() > 0) {
			result += lines[line] + "\n";
			++line;
		}
		i = line - 1;
		return result;
	}

	struct ScriptEdit
	{
		Script* script = nullptr;
		Sequence* curr_sequence = nullptr;
		ScriptNode curr_node;

		void start_node(NodeKind kind, const std::string& value)
		{
			finalize_current_node();
			curr_node = { kind, value };

			if (kind == NodeKind::Dialog)
			{
				/// @TODO how to interpret a value with parentheses? What does the spec say...?
				script->characters.insert(value);
			}
		}
		void finalize_current_node()
		{
			if (curr_node.kind != NodeKind::Unknown)
			{
				curr_sequence->nodes.push_back(curr_node);
				curr_node.kind = NodeKind::Unknown;
				curr_node.content = "";
			}
		}
		void append_text(const std::string& s)
		{
			if (curr_node.kind == NodeKind::Unknown)
				curr_node.kind = NodeKind::Action;
			if (curr_node.content.size())
				curr_node.content += '\n';
			curr_node.content += s;
		}

		void start_sequence(const string& name, bool interior, bool exterior)
		{
			finalize_current_sequence();
			script->sequences.emplace_back(Sequence(name, interior, exterior));
			script->sets.insert(script->sequences.back().as_string());
			curr_sequence = &script->sequences.back();
		}
		void finalize_current_sequence()
		{
			finalize_current_node();
			curr_sequence = nullptr;
		}
	};

	Script Script::parseFountain(const std::string& text)
	{
		Script script;
		ScriptEdit edit = { &script, &script.title };
		std::vector<std::string> lines = TextScanner::SplitLines(text);

		const char* title_page_tags[] = {
			"Title:", "Credit:", "Author:", "Source:", "Draft Date:",
			"Notes:", "Contact:", "Copyright:"
		};

		for (auto& line : lines)
		{
			auto s = StripLeadingWhitespace(line);

			if (beginsWith(s, "==="))
			{
				edit.start_node(NodeKind::Divider, s);
				edit.finalize_current_node();
				continue;
			}

			bool titled = false;
			for (auto t : title_page_tags)
			{
				if (beginsWith(s, t))
				{
					edit.start_node(NodeKind::KeyValue, std::string(t, strlen(t) - 1));
					titled = true;
					break;
				}
			}
			if (titled)
				continue;

			if (isShot(s))
			{
				bool interior, exterior;
				string shot_name = parseShot(s, interior, exterior);
				edit.start_sequence(shot_name, interior, exterior);
				continue;
			}

			if (isTransition(s))
			{
				edit.start_node(NodeKind::Transition, parseTransition(s));
				edit.finalize_current_node();
				continue;
			}

			if (isDialog(s))
			{
				if (s[0] == '@')
					s = s.substr(1);
				s = StripLeadingWhitespace(s);

				edit.start_node(NodeKind::Dialog, s);
				continue;
			}

			edit.append_text(s);
		}

		edit.finalize_current_sequence();
		return script;
	}

	Script Script::parseFountain(const filesystem::path& fountainFile)
	{
		FILE* f = open_file(fountainFile);
		if (!f)
			throw std::runtime_error("Couldn't open file");

		fseek(f, 0, SEEK_END);
		size_t len = ftell(f);
		fseek(f, 0, SEEK_SET);
		char* text = new char[len + 1];
		fread(text, 1, len, f);
		text[len] = '\0';
		fclose(f);
		char* end = text + len;
		std::string txt(text, end);
		delete[] text;
		return parseFountain(txt);
	}

}
<commit_msg>Put character in key field<commit_after>
// License: BSD 3-clause
// Copyright: Nick Porcino, 2017

#include "Screenplay.h"
#include <LabText/TextScanner.h>
#include <LabText/TextScanner.hpp>

namespace lab
{
	using namespace std;
	using namespace TextScanner;

	std::string ScriptNode::as_string() const
	{
		switch (kind)
		{
		case NodeKind::KeyValue: return key + ": " + content;
		case NodeKind::Divider: return content + "\n";
		case NodeKind::Character:
		case NodeKind::Location: return content + "\n";
		case NodeKind::Action: return content + "\n";
		case NodeKind::Dialog: return key + "\n" + content;
		case NodeKind::Direction: return content + "\n";
		case NodeKind::Transition: return ToUpper(content) + "\n";
			break;
		}

		return "";
	}

	Sequence::Sequence(const std::string & name_, bool interior, bool exterior)
		: interior(interior), exterior(exterior)
	{
		name = TextScanner::StripLeadingWhitespace(name_);
	}

	Sequence::Sequence(Sequence && rh)
		: name(rh.name), interior(rh.interior), exterior(rh.exterior)
	{
		nodes.swap(rh.nodes);
	}

	Sequence & Sequence::operator=(Sequence && rh)
	{
		interior = rh.interior;
		exterior = rh.exterior;
		name = rh.name;
		nodes.swap(rh.nodes);
		return *this;
	}

	std::string Sequence::as_string() const
	{
		std::string res;
		if (interior && exterior)
			res = "INT/EXT ";
		else if (interior)
			res = "INT. ";
		else if (exterior)
			res = "EXT. ";
		return res + name;
	}

	Script::Script(Script && rh) noexcept
		: title(std::move(rh.title))
		, characters(std::move(rh.characters))
		, sets(std::move(rh.sets))
		, sequences(std::move(rh.sequences))
	{
	}

#ifdef _MSC_VER
	inline FILE* open_file(const filesystem::path& p)
	{
		return _wfopen(p.c_str(), L"r");
	}
#else
	inline FILE* open_file(const filesystem::path& p)
	{
		return std::fopen(p.c_str(), "r");
	}
#endif

	bool isLineContinuation(const string & s)
	{
		if (s.length() < 1)
			return false;
		return s[0] == '\t' || (s[0] == ' ');
	}

	string parseValue(const string & s, const vector<string> & lines, size_t & i)
	{
		string result;
		size_t off = s.find(':');
		if (off != string::npos)
			result = s.substr(off);

		size_t line = i + 1;
		while (isLineContinuation(lines[line])) {
			result += lines[line];
			++line;
		}
		i = line - 1;
		return StripLeadingWhitespace(result);
	}

	bool lineIsUpperCase(const char * curr, const char * end)
	{
		const char * next = tsScanForBeginningOfNextLine(curr, end);
		while (next > curr) {
			if (*curr >= 'a' && *curr <= 'z')
				return false;
			++curr;
		}
		return true;
	}

	bool charIsEmphasis(char c) {
		return c == '*' || c == '_';
	}

#ifdef _MSC_VER
#define strnicmp _strnicmp
#endif

	bool beginsWith(const std::string& input, const char * match)
	{
		return !strnicmp(input.c_str(), match, (strlen(match)));
	}

	string parseShot(const std::string & input, bool & interior, bool & exterior)
	{
		interior = false;
		exterior = false;

		if (input.length() < 2)
			return "";

		if (input[0] == '.')
			return StripLeadingWhitespace(input.substr(1));

		if (beginsWith(input, "INT./EXT.") || beginsWith(input, "EXT./INT.")) {
			interior = true;
			exterior = true;
			return StripLeadingWhitespace(input.substr(9));
		}

		if (beginsWith(input, "INT./EXT") || beginsWith(input, "EXT./INT")) {
			interior = true;
			exterior = true;
			return StripLeadingWhitespace(input.substr(8));
		}

		if (beginsWith(input, "INT/EXT") || beginsWith(input, "EXT/INT")) {
			interior = true;
			exterior = true;
			return StripLeadingWhitespace(input.substr(7));
		}

		if (beginsWith(input, "INT ") || beginsWith(input, "EXT ") || beginsWith(input, "INT.") || beginsWith(input, "EXT.") || beginsWith(input, "I/E "))
		{
			interior = beginsWith(input, "I");
			exterior = beginsWith(input, "E") || beginsWith(input, "I/E ");
			return StripLeadingWhitespace(input.substr(4));
		}
		return "";
	}

	bool isShot(const std::string& input)
	{
		if (input.length() < 2)
			return false;

		if (input[0] == '.' && input[1] != '.')
			return true;

		return beginsWith(input, "INT ") || beginsWith(input, "EXT ")
			|| beginsWith(input, "INT.") || beginsWith(input, "EXT.")
			|| beginsWith(input, "INT/EXT") || beginsWith(input, "EXT/INT")
			|| beginsWith(input, "I/E ");
	}

	bool isTransition(const std::string & input)
	{
		if (!input.length())
			return false;

		string s = StripLeadingWhitespace(input);
		size_t len = s.length() - 1;
		if (len < 4)
			return false;

		if (s[0] == '>')
			return true;

		if (!lineIsUpperCase(input.c_str(), input.c_str() + input.length()))
			return false;

		const char * transitions[] = {
			"CUT TO BLACK",
			"cut to:",
			"CUT TO:",
			"INTERCUT WITH:",
			"FADE IN:",
			"TITLE OVER:",
			"SPLIT SCREEN:",
			"OPENING CREDITS",
			"END CREDITS"
		};

		for (auto str : transitions)
			if (s.find(str) != string::npos)
				return true;

		string end = s.substr(len - 3, len - 2);
		return beginsWith(end, " TO") || beginsWith(end, " IN");
	}

	string parseTransition(const std::string & input)
	{
		string r = StripLeadingWhitespace(input);
		if (r[0] == '>')
			r = r.substr(1);

		return StripTrailingWhitespace(StripLeadingWhitespace(r));
	}

	bool isDialog(const std::string & input)
	{
		if (input.length() < 2)
			return false;

		if (input[0] == '@')
			return true;

		if (isTransition(input))
			return false;

		return lineIsUpperCase(input.c_str(), input.c_str() + input.length());
	}

	string parseDialog(const string& s, string& character, const vector<string>& lines, size_t & i)
	{
		if (s[0] == '@')
			character = s.substr(1);
		else
			character = s;

		string result;

		size_t line = i + 1;
		while (line < lines.size() && lines[line].length() > 0) {
			result += lines[line] + "\n";
			++line;
		}
		i = line - 1;
		return result;
	}

	struct ScriptEdit
	{
		Script* script = nullptr;
		Sequence* curr_sequence = nullptr;
		ScriptNode curr_node;

		void start_node(NodeKind kind, const std::string& value)
		{
			finalize_current_node();
			curr_node = { kind, value, "" };

			if (kind == NodeKind::Dialog)
			{
				/// @TODO how to interpret a value with parentheses? What does the spec say...?
				script->characters.insert(value);
			}
		}
		void finalize_current_node()
		{
			if (curr_node.kind != NodeKind::Unknown)
			{
				curr_sequence->nodes.push_back(curr_node);
				curr_node.kind = NodeKind::Unknown;
				curr_node.key = "";
				curr_node.content = "";
			}
		}
		void append_text(const std::string& s)
		{
			if (curr_node.kind == NodeKind::Unknown)
				curr_node.kind = NodeKind::Action;
			if (curr_node.content.size())
				curr_node.content += '\n';
			curr_node.content += s;
		}

		void start_sequence(const string& name, bool interior, bool exterior)
		{
			finalize_current_sequence();
			script->sequences.emplace_back(Sequence(name, interior, exterior));
			script->sets.insert(script->sequences.back().as_string());
			curr_sequence = &script->sequences.back();
		}
		void finalize_current_sequence()
		{
			finalize_current_node();
			curr_sequence = nullptr;
		}
	};

	Script Script::parseFountain(const std::string& text)
	{
		Script script;
		ScriptEdit edit = { &script, &script.title };
		std::vector<std::string> lines = TextScanner::SplitLines(text);

		const char* title_page_tags[] =
		{
			"Title:", "Credit:", "Author:", "Source:", "Draft Date:",
			"Notes:", "Contact:", "Copyright:"
		};

		for (auto& line : lines)
		{
			auto s = StripLeadingWhitespace(line);

			if (beginsWith(s, "==="))
			{
				edit.start_node(NodeKind::Divider, s);
				edit.finalize_current_node();
				continue;
			}

			bool titled = false;
			for (auto t : title_page_tags)
			{
				if (beginsWith(s, t))
				{
					edit.start_node(NodeKind::KeyValue, std::string(t, strlen(t) - 1));
					titled = true;
					break;
				}
			}
			if (titled)
				continue;

			if (isShot(s))
			{
				bool interior, exterior;
				string shot_name = parseShot(s, interior, exterior);
				edit.start_sequence(shot_name, interior, exterior);
				continue;
			}

			if (isTransition(s))
			{
				edit.start_node(NodeKind::Transition, ToUpper(parseTransition(s)));
				edit.finalize_current_node();
				continue;
			}

			if (isDialog(s))
			{
				if (s[0] == '@')
					s = s.substr(1);
				s = StripLeadingWhitespace(s);

				edit.start_node(NodeKind::Dialog, s);
				continue;
			}

			edit.append_text(s);
		}

		edit.finalize_current_sequence();
		return script;
	}

	Script Script::parseFountain(const filesystem::path& fountainFile)
	{
		FILE* f = open_file(fountainFile);
		if (!f)
			throw std::runtime_error("Couldn't open file");

		fseek(f, 0, SEEK_END);
		size_t len = ftell(f);
		fseek(f, 0, SEEK_SET);
		char* text = new char[len + 1];
		fread(text, 1, len, f);
		text[len] = '\0';
		fclose(f);
		char* end = text + len;
		std::string txt(text, end);
		delete[] text;
		return parseFountain(txt);
	}

}
<|endoftext|>


<commit_before>#include "service.h"

Service::Service()
{

}

bool Service::addNewPersonToList(const vector<int> computerConnectionID,const string name,const string gender, const string birthYear, const string deathYear,const string comment)
{
    if(_cSPersonService.addNewPersonToList(name, gender,birthYear, deathYear, comment))
    {
        return true;
    }
    return false;
}

bool Service::addNewComputerToList(const vector<int> scientistConnectionID,const string name,const int designYear, const int buildYear, const string type, const bool created)
{
    Computer newComputer;
    int computerID = 0;
    if(_computerService.addNewComputerToList(newComputer, name, designYear, buildYear, type, created))
    {
        computerID = _dbCon.addComputer(newComputer);
        return true;
    }
    return false;
}

bool Service::removePersonFromList(const string id)
{
    /*if (_cSPersonService.removePersonFromList(id))
    {
        return true;
    }*/
    return false;
}

vector<CSPerson> Service::getComputerScientistList()
{
    updateComputerScientistList();
    return _computerScientists;
}
vector <string> Service::getComputerTypesList()
{
    // Not finished
    //Get list from DB

    return _computerTypes;
}
vector<Computer> Service::getComputerList()
{
    updateComputerList();
    return _computerList;
}
void Service::updateComputerList()
{
    _dbCon.getComputers(_computerList);
}
void Service::updateComputerScientistList()
{
    _dbCon.getComputerScientists(_computerScientists);
}

//Þau föll sem er ekki búið að fara yfir fyrir (aðlaga) Viku2

void Service::sortListAlphabetically()
{
    //_cSPersonService.sortByName();
}

void Service::sortListAlphabeticallyASC()
{
    //_cSPersonService.sortByNameASC();
}

void Service::sortListByGender()
{
    //_cSPersonService.sortByGender();
}

void Service::sortListByDeathYear()
{
    //_cSPersonService.sortByDeathYear();
}

void Service::sortListByBirthYear()
{
    //_cSPersonService.sortByBirthYear();
}

void Service::sortListByBirthYearASC()
{
    //_cSPersonService.sortByBirthYearASC();
}

void Service::sortListByAge()
{
    //_cSPersonService.sortByAge();
}

vector<CSPerson> Service::searchByName(const string searchString)
{
    vector <CSPerson> searchByName;// = _cSPersonService.searchByName(searchString);
    return searchByName;
}

vector<CSPerson> Service::searchByYearOfBirth(const string searchString)
{
    vector <CSPerson> searchByYOB;// = _cSPersonService.searchByYearOfBirth(searchString);
    return searchByYOB;
}

vector<CSPerson> Service::searchByYearOfDeath(const string searchString)
{
    vector <CSPerson> searchByYOD;// = _cSPersonService.searchByYearOfDeath(searchString);
    return searchByYOD;
}

vector<Computer> searchComputerByName(const string searchString)
{
    // TODO
    vector <Computer> searchByName;
    return searchByName;
}

vector<Computer> searchComputerByType(const string searchString)
{
    // TODO
    vector <Computer> searchByType;
    return searchByType;
}
vector<Computer> searchComputerByYear(const string searchString)
{
    // TODO
    vector <Computer> searchByYear;
    return searchByYear;
}

<commit_msg>sort functions for computer added in service class<commit_after>#include "service.h"

Service::Service()
{

}

bool Service::addNewPersonToList(const vector<int> computerConnectionID,const string name,const string gender, const string birthYear, const string deathYear,const string comment)
{
    if(_cSPersonService.addNewPersonToList(name, gender,birthYear, deathYear, comment))
    {
        return true;
    }
    return false;
}

bool Service::addNewComputerToList(const vector<int> scientistConnectionID,const string name,const int designYear, const int buildYear, const string type, const bool created)
{
    Computer newComputer;
    int computerID = 0;
    if(_computerService.addNewComputerToList(newComputer, name, designYear, buildYear, type, created))
    {
        computerID = _dbCon.addComputer(newComputer);
        return true;
    }
    return false;
}

bool Service::removePersonFromList(const string id)
{
    /*if (_cSPersonService.removePersonFromList(id))
    {
        return true;
    }*/
    return false;
}

vector<CSPerson> Service::getComputerScientistList()
{
    updateComputerScientistList();
    return _computerScientists;
}
vector <string> Service::getComputerTypesList()
{
    // Not finished
    //Get list from DB

    return _computerTypes;
}
vector<Computer> Service::getComputerList()
{
    updateComputerList();
    return _computerList;
}
void Service::updateComputerList()
{
    _dbCon.getComputers(_computerList);
}
void Service::updateComputerScientistList()
{
    _dbCon.getComputerScientists(_computerScientists);
}

//Þau föll sem er ekki búið að fara yfir fyrir (aðlaga) Viku2

void Service::sortListAlphabetically()
{
    //_cSPersonService.sortByName();
}

void Service::sortListAlphabeticallyASC()
{
    //_cSPersonService.sortByNameASC();
}

void Service::sortListByGender()
{
    //_cSPersonService.sortByGender();
}

void Service::sortListByDeathYear()
{
    //_cSPersonService.sortByDeathYear();
}

void Service::sortListByBirthYear()
{
    //_cSPersonService.sortByBirthYear();
}

void Service::sortListByBirthYearASC()
{
    //_cSPersonService.sortByBirthYearASC();
}

void Service::sortListByAge()
{
    //_cSPersonService.sortByAge();
}

vector<CSPerson> Service::searchByName(const string searchString)
{
    vector <CSPerson> searchByName;// = _cSPersonService.searchByName(searchString);
    return searchByName;
}

vector<CSPerson> Service::searchByYearOfBirth(const string searchString)
{
    vector <CSPerson> searchByYOB;// = _cSPersonService.searchByYearOfBirth(searchString);
    return searchByYOB;
}

vector<CSPerson> Service::searchByYearOfDeath(const string searchString)
{
    vector <CSPerson> searchByYOD;// = _cSPersonService.searchByYearOfDeath(searchString);
    return searchByYOD;
}

vector<Computer> Service::searchComputerByName(const string searchString)
{
    // TODO
    vector <Computer> searchByName;
    return searchByName;
}

vector<Computer> Service::searchComputerByType(const string searchString)
{
    // TODO
    vector <Computer> searchByType;
    return searchByType;
}
vector<Computer> Service::searchComputerByYear(const string searchString)
{
    // TODO
    vector <Computer> searchByYear;
    return searchByYear;
}

<|endoftext|>


<commit_before>/*
    FLTKKeyboardWidget.hpp:

    Copyright (C) 2006 Steven Yi

    This file is part of Csound.

    The Csound Library is free software; you can redistribute it
    and/or modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    Csound is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Csound; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA
*/

#include "FLTKKeyboardWidget.hpp"

static void allNotesOff(Fl_Widget *widget, void * v) {
    FLTKKeyboardWidget *win = (FLTKKeyboardWidget *)v;
    win->keyboard->allNotesOff();
}

static void channelChange(Fl_Widget *widget, void * v) {
    Fl_Spinner *spinner = (Fl_Spinner *)widget;
    FLTKKeyboardWidget *win = (FLTKKeyboardWidget *)v;

    win->lock();

    int channel = (int)spinner->value() - 1;

    win->keyboardMapping->setCurrentChannel(channel);

    win->bankChoice->value(win->keyboardMapping->getCurrentBank());

    win->setProgramNames();

    win->unlock();
}

static void bankChange(Fl_Widget *widget, void * v) {
    Fl_Choice *choice = (Fl_Choice *)widget;
    FLTKKeyboardWidget *win = (FLTKKeyboardWidget *)v;

    win->lock();

    win->keyboardMapping->setCurrentBank((int)choice->value());

    win->setProgramNames();

    win->unlock();
}

static void programChange(Fl_Widget *widget, void * v) {
    Fl_Choice *choice = (Fl_Choice *)widget;
    FLTKKeyboardWidget *win = (FLTKKeyboardWidget *)v;

    win->lock();

    win->keyboardMapping->setCurrentProgram((int)choice->value());

    win->unlock();
}

FLTKKeyboardWidget::FLTKKeyboardWidget(CSOUND *csound,
          const char *deviceMap,
          int X, int Y)
    : Fl_Group(X, Y, 624, 120)
{

    this->csound = csound;
    this->mutex = csound->Create_Mutex(0);

    this->keyboardMapping = new KeyboardMapping(csound, deviceMap);

    this->begin();

    int row1 = 0;
    int row2 = row1 + 20;
    int row3 = row2 + 20;

    this->channelSpinner = new Fl_Spinner(60, row1, 80, 20, "Channel");
    channelSpinner->maximum(16);
    channelSpinner->minimum(1);
    this->channelSpinner->callback((Fl_Callback*) channelChange, this);

    this->bankChoice = new Fl_Choice(180, row1, 180, 20, "Bank");
    this->programChoice = new Fl_Choice(420, row1, 200, 20, "Program");

    bankChoice->clear();

    for(unsigned int i = 0; i < keyboardMapping->banks.size(); i++) {
            bankChoice->add(keyboardMapping->banks[i]->name);
    }

    bankChoice->value(0);

    setProgramNames();

    this->bankChoice->callback((Fl_Callback*)bankChange, this);
    this->programChoice->callback((Fl_Callback*)programChange, this);

    this->allNotesOffButton = new Fl_Button(0, row2, 623, 20, "All Notes Off");
    this->allNotesOffButton->callback((Fl_Callback*) allNotesOff, this);

    this->keyboard = new FLTKKeyboard(csound, 0, row3, 624, 80, "Keyboard");

    this->end();

}

FLTKKeyboardWidget::~FLTKKeyboardWidget() {
    if (mutex) {
        csound->DestroyMutex(mutex);
        mutex = (void*) 0;
    }
    delete keyboardMapping;
}

void FLTKKeyboardWidget::setProgramNames() {

    Bank* bank = keyboardMapping->banks[keyboardMapping->getCurrentBank()];

    programChoice->clear();

    for( vector<Program>::iterator iter = bank->programs.begin();
            iter != bank->programs.end(); iter++ ) {
            programChoice->add((*iter).name);
    }

    programChoice->value(bank->currentProgram);
}

int FLTKKeyboardWidget::handle(int event) {
    //this->csound->Message(this->csound, "Keyboard event: %d\n", event);

    switch(event) {
        case FL_KEYDOWN:
                return this->keyboard->handle(event);
        case FL_KEYUP:
                return this->keyboard->handle(event);
//        case FL_DEACTIVATE:
//              this->keyboard->allNotesOff();
//              csound->Message(csound, "Deactivate\n");
//              return 1;
        default:
            return Fl_Group::handle(event);
    }

}

void FLTKKeyboardWidget::lock() {
    if(mutex) {
        csound->LockMutex(mutex);
    }
}

void FLTKKeyboardWidget::unlock() {
    if(mutex) {
        csound->UnlockMutex(mutex);
    }
}
<commit_msg>fixes for x and y values<commit_after>/*
    FLTKKeyboardWidget.hpp:

    Copyright (C) 2006 Steven Yi

    This file is part of Csound.

    The Csound Library is free software; you can redistribute it
    and/or modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    Csound is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Csound; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA
*/

#include "FLTKKeyboardWidget.hpp"

static void allNotesOff(Fl_Widget *widget, void * v) {
    FLTKKeyboardWidget *win = (FLTKKeyboardWidget *)v;
    win->keyboard->allNotesOff();
}

static void channelChange(Fl_Widget *widget, void * v) {
    Fl_Spinner *spinner = (Fl_Spinner *)widget;
    FLTKKeyboardWidget *win = (FLTKKeyboardWidget *)v;

    win->lock();

    int channel = (int)spinner->value() - 1;

    win->keyboardMapping->setCurrentChannel(channel);

    win->bankChoice->value(win->keyboardMapping->getCurrentBank());

    win->setProgramNames();

    win->unlock();
}

static void bankChange(Fl_Widget *widget, void * v) {
    Fl_Choice *choice = (Fl_Choice *)widget;
    FLTKKeyboardWidget *win = (FLTKKeyboardWidget *)v;

    win->lock();

    win->keyboardMapping->setCurrentBank((int)choice->value());

    win->setProgramNames();

    win->unlock();
}

static void programChange(Fl_Widget *widget, void * v) {
    Fl_Choice *choice = (Fl_Choice *)widget;
    FLTKKeyboardWidget *win = (FLTKKeyboardWidget *)v;

    win->lock();

    win->keyboardMapping->setCurrentProgram((int)choice->value());

    win->unlock();
}

FLTKKeyboardWidget::FLTKKeyboardWidget(CSOUND *csound,
          const char *deviceMap,
          int X, int Y)
    : Fl_Group(X, Y, 624, 120)
{

    this->csound = csound;
    this->mutex = csound->Create_Mutex(0);

    this->keyboardMapping = new KeyboardMapping(csound, deviceMap);

    this->begin();

    int baseX = this->x();
    int baseY = this->y();

    int row1 = baseY;
    int row2 = row1 + 20;
    int row3 = row2 + 20;

    this->channelSpinner = new Fl_Spinner(baseX + 60, row1, 80, 20, "Channel");
    channelSpinner->maximum(16);
    channelSpinner->minimum(1);
    this->channelSpinner->callback((Fl_Callback*) channelChange, this);

    this->bankChoice = new Fl_Choice(baseX + 180, row1, 180, 20, "Bank");
    this->programChoice = new Fl_Choice(baseX + 420, row1, 200, 20, "Program");

    bankChoice->clear();

    for(unsigned int i = 0; i < keyboardMapping->banks.size(); i++) {
            bankChoice->add(keyboardMapping->banks[i]->name);
    }

    bankChoice->value(0);

    setProgramNames();

    this->bankChoice->callback((Fl_Callback*)bankChange, this);
    this->programChoice->callback((Fl_Callback*)programChange, this);

    this->allNotesOffButton = new Fl_Button(baseX, row2, 623, 20, "All Notes Off");
    this->allNotesOffButton->callback((Fl_Callback*) allNotesOff, this);

    this->keyboard = new FLTKKeyboard(csound, baseX, row3, 624, 80, "Keyboard");

    this->end();

}

FLTKKeyboardWidget::~FLTKKeyboardWidget() {
    if (mutex) {
        csound->DestroyMutex(mutex);
        mutex = (void*) 0;
    }
    delete keyboardMapping;
}

void FLTKKeyboardWidget::setProgramNames() {

    Bank* bank = keyboardMapping->banks[keyboardMapping->getCurrentBank()];

    programChoice->clear();

    for( vector<Program>::iterator iter = bank->programs.begin();
            iter != bank->programs.end(); iter++ ) {
            programChoice->add((*iter).name);
    }

    programChoice->value(bank->currentProgram);
}

int FLTKKeyboardWidget::handle(int event) {
    switch(event) {
        case FL_KEYDOWN:
                return this->keyboard->handle(event);
        case FL_KEYUP:
                return this->keyboard->handle(event);
//        case FL_DEACTIVATE:
//              this->keyboard->allNotesOff();
//              csound->Message(csound, "Deactivate\n");
//              return 1;
        default:
//        this->csound->Message(this->csound, "Keyboard event: %d\n", event);
            return Fl_Group::handle(event);
    }

}

void FLTKKeyboardWidget::lock() {
    if(mutex) {
        csound->LockMutex(mutex);
    }
}

void FLTKKeyboardWidget::unlock() {
    if(mutex) {
        csound->UnlockMutex(mutex);
    }
}
<|endoftext|>


<commit_before>
/**
 *
 * Copyright (C) 2013 - 2014 Jolla Ltd.
 * Contact: Thomas Perl <thomas.perl@jollamobile.com>
 * All rights reserved.
 *
 * This file is part of libsailfishapp
 *
 * You may use this file under the terms of the GNU Lesser General
 * Public License version 2.1 as published by the Free Software Foundation
 * and appearing in the file license.lgpl included in the packaging
 * of this file.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file license.lgpl included in the packaging
 * of this file.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 **/

#include "sailfishapp.h"
#include "sailfishapp_priv.h"

#include <QtGlobal>

#include <QGuiApplication>
#include <QScopedPointer>
#include <QScreen>
#include <QSize>
#include <QQuickView>
#include <QString>
#include <QDir>
#include <QQmlEngine>

namespace SailfishApp {

QGuiApplication *application(int &argc, char **argv)
{
    static QGuiApplication *app = NULL;

    if (app == NULL) {
        app = SailfishAppPriv::application(argc, argv);
    } else {
        qWarning("SailfishApp::application() called multiple times");
    }

    return app;
}

QQuickView *createView()
{
    QQuickWindow::setDefaultAlphaBuffer(true);

    QQuickView *view = SailfishAppPriv::view();

    // Add import path to allow private QML import modules in /usr/share/<name>/
    view->engine()->addImportPath(SailfishAppPriv::dataDir());

    return view;
}

QUrl pathTo(const QString &filename)
{
    return QUrl::fromLocalFile(QDir::cleanPath(QString("%1/%2")
        .arg(SailfishAppPriv::dataDir())
        .arg(filename)));
}

QUrl pathToMainQml()
{
    QString mainQml = QString("qml/%1.qml").arg(SailfishAppPriv::appName());
    return pathTo(mainQml);
}

int main(int &argc, char **argv)
{
    QScopedPointer<QGuiApplication> app(SailfishApp::application(argc, argv));
    QScopedPointer<QQuickView> view(SailfishApp::createView());

    view->setSource(SailfishApp::pathToMainQml());
    view->show();

    return app->exec();
}

}; /* namespace SailfishApp */
<commit_msg>[libsailfishapp] Resize root object to the view size. Fixes JB#40253<commit_after>
/**
 *
 * Copyright (C) 2013 - 2014 Jolla Ltd.
 * Contact: Thomas Perl <thomas.perl@jollamobile.com>
 * All rights reserved.
 *
 * This file is part of libsailfishapp
 *
 * You may use this file under the terms of the GNU Lesser General
 * Public License version 2.1 as published by the Free Software Foundation
 * and appearing in the file license.lgpl included in the packaging
 * of this file.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file license.lgpl included in the packaging
 * of this file.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 **/

#include "sailfishapp.h"
#include "sailfishapp_priv.h"

#include <QtGlobal>

#include <QGuiApplication>
#include <QScopedPointer>
#include <QScreen>
#include <QSize>
#include <QQuickView>
#include <QString>
#include <QDir>
#include <QQmlEngine>

namespace SailfishApp {

QGuiApplication *application(int &argc, char **argv)
{
    static QGuiApplication *app = NULL;

    if (app == NULL) {
        app = SailfishAppPriv::application(argc, argv);
    } else {
        qWarning("SailfishApp::application() called multiple times");
    }

    return app;
}

QQuickView *createView()
{
    QQuickWindow::setDefaultAlphaBuffer(true);

    QQuickView *view = SailfishAppPriv::view();

    // Add import path to allow private QML import modules in /usr/share/<name>/
    view->engine()->addImportPath(SailfishAppPriv::dataDir());
    view->setResizeMode(QQuickView::SizeRootObjectToView);

    return view;
}

QUrl pathTo(const QString &filename)
{
    return QUrl::fromLocalFile(QDir::cleanPath(QString("%1/%2")
        .arg(SailfishAppPriv::dataDir())
        .arg(filename)));
}

QUrl pathToMainQml()
{
    QString mainQml = QString("qml/%1.qml").arg(SailfishAppPriv::appName());
    return pathTo(mainQml);
}

int main(int &argc, char **argv)
{
    QScopedPointer<QGuiApplication> app(SailfishApp::application(argc, argv));
    QScopedPointer<QQuickView> view(SailfishApp::createView());

    view->setSource(SailfishApp::pathToMainQml());
    view->show();

    return app->exec();
}

}; /* namespace SailfishApp */
<|endoftext|>


<commit_before>#pragma once

#include <type_traits>

#include "ksp_plugin/plugin.hpp"

// DLL-exported functions for interfacing with Platform Invocation Services.

#if defined(DLLEXPORT)
#error "DLLEXPORT already defined"
#else
#if defined(_WIN32)
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __attribute__((visibility("default")))
#endif
#endif

namespace principia {
namespace ksp_plugin {

extern "C"
struct XYZ {
  double x, y, z;
};

static_assert(std::is_standard_layout<XYZ>::value,
              "XYZ is used for interfacing");

// Sets stderr to log INFO, and redirects stderr, which Unity does not log, to
// "<KSP directory>/stderr.log". This provides an easily accessible file
// containing a sufficiently verbose log of the latest session, instead of
// requiring users to dig in the archive of all past logs at all severities.
// This archive is written to
// "<KSP directory>/glog/Principia/<SEVERITY>.<date>-<time>.<pid>",
// where date and time are in ISO 8601 basic format.
// TODO(egg): libglog should really be statically linked, what happens if two
// plugins use glog?
extern "C" DLLEXPORT
void InitGoogleLogging();

// Exports |LOG(SEVERITY) << message| for fast logging from the C# adapter.
// This will always evaluate its argument even if the corresponding log severity
// is disabled, so it is less efficient than LOG(INFO). It will not report the
// line and file of the caller.
extern "C" DLLEXPORT
void LogInfo(char const* message);
extern "C" DLLEXPORT
void LogWarning(char const* message);
extern "C" DLLEXPORT
void LogError(char const* message);
extern "C" DLLEXPORT
void LogFatal(char const* message);

// Returns a pointer to a plugin constructed with the arguments given.
// The caller takes ownership of the result.
extern "C" DLLEXPORT
Plugin* NewPlugin(double const initial_time,
                  int const sun_index,
                  double const sun_gravitational_parameter,
                  double const planetarium_rotation_in_degrees);

// Deletes and nulls |*plugin|.
// |plugin| should not be null. No transfer of ownership of |*plugin|,
// takes ownership of |**plugin|.
extern "C" DLLEXPORT
void DeletePlugin(Plugin const** const plugin);

// Calls |plugin->InsertCelestial| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
void InsertCelestial(Plugin* const plugin,
                     int const celestial_index,
                     double const gravitational_parameter,
                     int const parent_index,
                     XYZ const from_parent_position,
                     XYZ const from_parent_velocity);

// Calls |plugin->UpdateCelestialHierarchy| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
void UpdateCelestialHierarchy(Plugin const* const plugin,
                              int const celestial_index,
                              int const parent_index);

// Calls |plugin->InsertOrKeepVessel| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
void InsertOrKeepVessel(Plugin* const plugin,
                        char const* vessel_guid,
                        int const parent_index);

// Calls |plugin->SetVesselStateOffset| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
void SetVesselStateOffset(Plugin const* const plugin,
                          char const* vessel_guid,
                          XYZ const from_parent_position,
                          XYZ const from_parent_velocity);

// Calls |plugin->VesselDisplacementFromParent| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
XYZ VesselDisplacementFromParent(Plugin const* const plugin,
                                 char const* vessel_guid);

// Calls |plugin->VesselParentRelativeVelocity| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
XYZ VesselParentRelativeVelocity(Plugin const* const plugin,
                                 char const* vessel_guid);

// Calls |plugin->CelestialDisplacementFromParent| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
XYZ CelestialDisplacementFromParent(Plugin const* const plugin,
                                    int const celestial_index);

// Calls |plugin->CelestialParentRelativeVelocity| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
XYZ CelestialParentRelativeVelocity(Plugin const* const plugin,
                                    int const celestial_index);

// Says hello, convenient for checking that calls to the DLL work.
extern "C" DLLEXPORT
char const* SayHello();

}  // namespace ksp_plugin
}  // namespace principia

#undef DLLEXPORT
<commit_msg>cdecl<commit_after>#pragma once

#include <type_traits>

#include "ksp_plugin/plugin.hpp"

// DLL-exported functions for interfacing with Platform Invocation Services.

#if defined(DLLEXPORT)
#error "DLLEXPORT already defined"
#elif defined(CDECL)
#error "CDECL already defined"
#else
#if defined(_WIN32) || defined(_WIN64)
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __attribute__((visibility("default")))
#endif
// Architecture macros from http://goo.gl/ZypnO8.
// We use cdecl on x86, the calling convention is unambiguous on x86-64.
#if defined(__i386) || defined(_M_IX86)
#if defined(_MSC_VER) || defined(__clang__)
#define CDECL __cdecl
#elif defined(__GNUC__) || defined(__INTEL_COMPILER)
#define CDECL __attribute__((cdecl))
#else
#error "Get a real compiler"
#endif
#elif defined(_M_X64) || defined(__x86_64__)
#define CDECL
#else
#error "Have you tried a Cray-1?"
#endif
#endif

namespace principia {
namespace ksp_plugin {

extern "C"
struct XYZ {
  double x, y, z;
};

static_assert(std::is_standard_layout<XYZ>::value,
              "XYZ is used for interfacing");

// Sets stderr to log INFO, and redirects stderr, which Unity does not log, to
// "<KSP directory>/stderr.log". This provides an easily accessible file
// containing a sufficiently verbose log of the latest session, instead of
// requiring users to dig in the archive of all past logs at all severities.
// This archive is written to
// "<KSP directory>/glog/Principia/<SEVERITY>.<date>-<time>.<pid>",
// where date and time are in ISO 8601 basic format.
// TODO(egg): libglog should really be statically linked, what happens if two
// plugins use glog?
extern "C" DLLEXPORT
void CDECL InitGoogleLogging();

// Exports |LOG(SEVERITY) << message| for fast logging from the C# adapter.
// This will always evaluate its argument even if the corresponding log severity
// is disabled, so it is less efficient than LOG(INFO). It will not report the
// line and file of the caller.
extern "C" DLLEXPORT
void CDECL LogInfo(char const* message);
extern "C" DLLEXPORT
void CDECL LogWarning(char const* message);
extern "C" DLLEXPORT
void CDECL LogError(char const* message);
extern "C" DLLEXPORT
void CDECL LogFatal(char const* message);

// Returns a pointer to a plugin constructed with the arguments given.
// The caller takes ownership of the result.
extern "C" DLLEXPORT
Plugin* CDECL NewPlugin(double const initial_time,
                  int const sun_index,
                  double const sun_gravitational_parameter,
                  double const planetarium_rotation_in_degrees);

// Deletes and nulls |*plugin|.
// |plugin| should not be null. No transfer of ownership of |*plugin|,
// takes ownership of |**plugin|.
extern "C" DLLEXPORT
void CDECL DeletePlugin(Plugin const** const plugin);

// Calls |plugin->InsertCelestial| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
void CDECL InsertCelestial(Plugin* const plugin,
                     int const celestial_index,
                     double const gravitational_parameter,
                     int const parent_index,
                     XYZ const from_parent_position,
                     XYZ const from_parent_velocity);

// Calls |plugin->UpdateCelestialHierarchy| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
void CDECL UpdateCelestialHierarchy(Plugin const* const plugin,
                              int const celestial_index,
                              int const parent_index);

// Calls |plugin->InsertOrKeepVessel| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
void CDECL InsertOrKeepVessel(Plugin* const plugin,
                              char const* vessel_guid,
                              int const parent_index);

// Calls |plugin->SetVesselStateOffset| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
void CDECL SetVesselStateOffset(Plugin const* const plugin,
                                char const* vessel_guid,
                                XYZ const from_parent_position,
                                XYZ const from_parent_velocity);

// Calls |plugin->VesselDisplacementFromParent| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
XYZ CDECL VesselDisplacementFromParent(Plugin const* const plugin,
                                       char const* vessel_guid);

// Calls |plugin->VesselParentRelativeVelocity| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
XYZ CDECL VesselParentRelativeVelocity(Plugin const* const plugin,
                                       char const* vessel_guid);

// Calls |plugin->CelestialDisplacementFromParent| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
XYZ CDECL CelestialDisplacementFromParent(Plugin const* const plugin,
                                          int const celestial_index);

// Calls |plugin->CelestialParentRelativeVelocity| with the arguments given.
// |plugin| should not be null. No transfer of ownership.
extern "C" DLLEXPORT
XYZ CDECL CelestialParentRelativeVelocity(Plugin const* const plugin,
                                          int const celestial_index);

// Says hello, convenient for checking that calls to the DLL work.
extern "C" DLLEXPORT
char const* CDECL SayHello();

}  // namespace ksp_plugin
}  // namespace principia

#undef DLLEXPORT
#undef CDECL
<|endoftext|>


<commit_before>// NanoWin32
// -----------------------------------------------------------------------
// Simple library to subset Win32(64) API functions implemenation on POSIX
// This software distributed by MIT license

// ShellEx functions

#include "NanoWinShellEx.h"

#include "NanoWinError.h"
#include "NanoWinFileSys.h"

NW_EXTERN_C_BEGIN

extern int SHCreateDirectoryExW
           (
            HWND                       hwnd,
            LPCWSTR                    pszPath,
            const SECURITY_ATTRIBUTES *psa
           )
{
  // TODO: Refine implemenation (create folders among full path)

  // Error codes: (at least): [see doc]
  // ERROR_SUCCESS:
  // ERROR_FILE_EXISTS:
  // ERROR_ALREADY_EXISTS:

  if (hwnd != NULL) { return(NanoWinSetLastError(NW_DEFAULT_ERROR_AT_FAIL)); }
  if (CreateDirectoryW(pszPath, const_cast<SECURITY_ATTRIBUTES*>(psa)))
  {
    return(ERROR_SUCCESS);
  }
  else if (GetLastError() != ERROR_SUCCESS)
  {
    return(GetLastError());
  }
  else // GetLastError() not set, but we have failed to action
  {
    return(NanoWinSetLastError(NW_DEFAULT_ERROR_AT_FAIL));
  }
}

extern int SHCreateDirectoryExA
           (
            HWND                       hwnd,
            LPCSTR                     pszPath,
            const SECURITY_ATTRIBUTES *psa
           )
{
  // TODO: Refine implemenation (create folders among full path)

  // Error codes: (at least): [see doc]
  // ERROR_SUCCESS:
  // ERROR_FILE_EXISTS:
  // ERROR_ALREADY_EXISTS:

  if (hwnd != NULL) { return(NanoWinSetLastError(NW_DEFAULT_ERROR_AT_FAIL)); }
  if (CreateDirectoryA(pszPath, const_cast<SECURITY_ATTRIBUTES*>(psa)))
  {
    return(ERROR_SUCCESS);
  }
  else if (GetLastError() != ERROR_SUCCESS)
  {
    return(GetLastError());
  }
  else // GetLastError() not set, but we have failed to action
  {
    return(NanoWinSetLastError(NW_DEFAULT_ERROR_AT_FAIL));
  }
}

NW_EXTERN_C_END
<commit_msg>intermediate subdirs creation support added to SHCreateDirectoryEx function<commit_after>// NanoWin32
// -----------------------------------------------------------------------
// Simple library to subset Win32(64) API functions implemenation on POSIX
// This software distributed by MIT license

// ShellEx functions

#include <string.h>

#include "NanoWinShellEx.h"

#include "NanoWinError.h"
#include "NanoWinFileSys.h"
#include "NanoWinStrConvert.h"

#define NanoWinShellExDirSepChar    ('/')
#define NanoWinShellExDirSepAltChar ('\\')

NW_EXTERN_C_BEGIN

extern int SHCreateDirectoryExW
           (
            HWND                       hwnd,
            LPCWSTR                    pszPath,
            const SECURITY_ATTRIBUTES *psa
           )
{
  try
  {
    return SHCreateDirectoryExA(hwnd,NanoWin::StrConverter::Convert(pszPath).c_str(),psa);
  }
  catch (NanoWin::StrConverter::Error)
  {
    SetLastError(ERROR_NO_UNICODE_TRANSLATION);

    return ERROR_NO_UNICODE_TRANSLATION;
  }
}

// returns either position of found char or strlen(str) if char wasn't found
static size_t StrFindChars(const char *str, char ch, char altCh)
{
  const char *ptr = str;

  while (*ptr != '\0' && *ptr != ch && *ptr != altCh)
  {
    ptr++;
  }

  return (size_t)(ptr - str);
}

extern int SHCreateDirectoryExA
           (
            HWND                       hwnd,
            LPCSTR                     pszPath,
            const SECURITY_ATTRIBUTES *psa
           )
{
  // Error codes: (at least): [see doc]
  // ERROR_SUCCESS:
  // ERROR_FILE_EXISTS:
  // ERROR_ALREADY_EXISTS:

  constexpr size_t PATH_MAX_LEN = (248 - 1); // according to MS documentation

  if (hwnd != NULL) { return(NanoWinSetLastError(NW_DEFAULT_ERROR_AT_FAIL)); }

  bool   ok     = true;
  size_t sepPos = StrFindChars(pszPath,NanoWinShellExDirSepChar,NanoWinShellExDirSepAltChar);

  if (pszPath[sepPos] != '\0')
  {
    // subdirs(or absolute path) found in path, need to check if parent dirs need to be created

    char subPath[PATH_MAX_LEN + 1];

    if (sepPos < PATH_MAX_LEN)
    {
      memcpy(subPath,pszPath,sepPos);

      subPath[sepPos] = NanoWinShellExDirSepChar;
      subPath[++sepPos]   = '\0';

      size_t startPos = 0;
      bool   pathExists = false;

      // sepPos points to the char after separator
      // subPath contains current path prefix with trailing path separator (if any)
      do
      {
        pathExists = PathFileExistsA(subPath);

        if (!pathExists)
        {
          ok = CreateDirectoryA(subPath, const_cast<SECURITY_ATTRIBUTES*>(psa));
        }

        if (ok)
        {
          startPos = sepPos;

          if (pszPath[startPos] != '\0')
          {
            sepPos += StrFindChars(&pszPath[startPos],NanoWinShellExDirSepChar,NanoWinShellExDirSepAltChar);

            memcpy(&subPath[startPos],&pszPath[startPos],sepPos - startPos + 1);

            if (subPath[sepPos] != '\0')
            {
              subPath[sepPos]   = NanoWinShellExDirSepChar;
              subPath[++sepPos] = '\0';
            }
          }
        }
      } while (ok && pszPath[startPos] != '\0');

      if (ok && pathExists)
      {
        ok = false; SetLastError(ERROR_ALREADY_EXISTS);
      }
    }
    else
    {
      ok = false;

      SetLastError(ERROR_FILENAME_EXCED_RANGE);
    }
  }
  else
  {
    // no subdirs found in path, just create directory

    ok = CreateDirectoryA(pszPath, const_cast<SECURITY_ATTRIBUTES*>(psa));
  }

  if (ok)
  {
    return(ERROR_SUCCESS);
  }
  else if (GetLastError() != ERROR_SUCCESS)
  {
    return(GetLastError());
  }
  else // GetLastError() not set, but we have failed to action
  {
    return(NanoWinSetLastError(NW_DEFAULT_ERROR_AT_FAIL));
  }
}

NW_EXTERN_C_END
<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE TestImpedanceSpectroscopy
#define BOOST_TEST_MAIN
#include <cap/energy_storage_device.h>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/test/unit_test.hpp>
#include <gsl/gsl_fft_real.h>
#include <iostream>
#include <fstream>
#include <complex>

namespace cap {

std::complex<double>
measure_impedance(std::shared_ptr<cap::EnergyStorageDevice> dev, std::shared_ptr<boost::property_tree::ptree const> database);

std::complex<double>
measure_impedance(std::shared_ptr<cap::EnergyStorageDevice> dev, std::shared_ptr<boost::property_tree::ptree const> database)
{
    double const frequency       = database->get<double>("frequency"      );
    double const amplitude       = database->get<double>("amplitude"      );
    int    const cycles          = database->get<int   >("cycles"         );
    int    const steps_per_cycle = database->get<int   >("steps_per_cycle");
    double const initial_voltage = 0.0;
    std::vector<int> const powers_of_two =
        { 1, 2 ,4, 8, 16,
          32, 64, 128, 256, 512,
          1024, 2048, 4096, 8192, 16384,
          32768, 65536, 131072, 262144, 524288
        }; // first 20 powers of two
    if (find(powers_of_two.begin(), powers_of_two.end(), (cycles-1)*steps_per_cycle) == powers_of_two.end())
        throw std::runtime_error("(cycles-1)*steps_per_cycle must be a power of two");

    double       time      = 0.0;
    double const time_step = 1.0 / frequency / steps_per_cycle;
    double const phase     = std::asin(initial_voltage / amplitude);
    double const pi        = std::acos(-1.0);
    double const angular_frequency = 2.0 * pi * frequency;
    dev->reset_voltage(initial_voltage);
    double voltage;
    double current;
    std::vector<double> excitation;
    std::vector<double> response;
    for (int n = 0; n < cycles*steps_per_cycle; ++n)
    {
          time += time_step;
          voltage = amplitude * std::sin(angular_frequency * time + phase);
          dev->evolve_one_time_step_changing_voltage(time_step, voltage);
          dev->get_current(current);
          if (n >= steps_per_cycle)
          {
              excitation.push_back(voltage);
              response  .push_back(current);
          }
    }
    gsl_fft_real_radix2_transform(&(excitation[0]), 1, excitation.size());
    gsl_fft_real_radix2_transform(&(response  [0]), 1, response  .size());
    std::complex<double> const impedance =
        std::complex<double>(excitation[(cycles-1)], excitation[excitation.size()-(cycles-1)])
        /
        std::complex<double>(response  [(cycles-1)], response  [response  .size()-(cycles-1)]);
    return impedance;
}

void impedance_spectroscopy(std::shared_ptr<cap::EnergyStorageDevice> dev, std::shared_ptr<boost::property_tree::ptree const> database, std::ostream & os = std::cout)
{
    double const frequency_lower_limit = database->get<double>("frequency_lower_limit");
    double const frequency_upper_limit = database->get<double>("frequency_upper_limit");
    double const ratio                 = database->get<double>("ratio"                );
    double const pi                    = boost::math::constants::pi<double>();
    std::shared_ptr<boost::property_tree::ptree> tmp =
        std::make_shared<boost::property_tree::ptree>(*database);
    for (double frequency = frequency_lower_limit; frequency <= frequency_upper_limit; frequency *= ratio)
    {
        tmp->put("frequency", frequency);
        std::complex<double> impedance =
            measure_impedance(dev, tmp);
        os<<boost::format( "  %20.15e  %20.15e  %20.15e  %20.15e  %20.15e  \n")
            % frequency
            % impedance.real()
            % impedance.imag()
            % std::abs(impedance)
            % (std::arg(impedance) * 180.0 / pi)
            ;
    }
}

} // end namespace cap

BOOST_AUTO_TEST_CASE( test_measure_impedance )
{
    // parse input file
    std::shared_ptr<boost::property_tree::ptree> input_database =
        std::make_shared<boost::property_tree::ptree>();
    read_xml("input_impedance_spectroscopy", *input_database);

    std::string const type = input_database->get<std::string>("device.type");
    // current test will only work for series or parallel rc circuit
    if ((type.compare("SeriesRC") != 0) && (type.compare("ParallelRC") != 0))
        throw std::runtime_error("test measure impedance check not implemented for "+type);

    // build an energy storage system
    std::shared_ptr<boost::property_tree::ptree> device_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("device"));
    std::shared_ptr<cap::EnergyStorageDevice> device =
        cap::buildEnergyStorageDevice(std::make_shared<cap::Parameters>(device_database));

    double const frequency_lower_limit = input_database->get<double>("impedance_spectroscopy.frequency_lower_limit");
    double const frequency_upper_limit = input_database->get<double>("impedance_spectroscopy.frequency_upper_limit");
    double const ratio                 = input_database->get<double>("impedance_spectroscopy.ratio"                );
    double const percent_tolerance     = input_database->get<double>("impedance_spectroscopy.percent_tolerance"    );
    double const series_resistance     = input_database->get<double>("device.series_resistance"                    );
    double const parallel_resistance   = input_database->get<double>("device.parallel_resistance"                  );
    double const capacitance           = input_database->get<double>("device.capacitance"                          );
    double const pi                    = boost::math::constants::pi<double>();

    std::shared_ptr<boost::property_tree::ptree> impedance_spectroscopy_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("impedance_spectroscopy"));
    std::fstream fout("computed_vs_exact_impedance_spectroscopy_data", std::fstream::out);
    for (double frequency = frequency_lower_limit; frequency < frequency_upper_limit; frequency *= ratio)
    {
        double const angular_frequency = 2.0 * pi * frequency;
        impedance_spectroscopy_database->put("frequency", frequency);
        std::complex<double> computed_impedance = cap::measure_impedance(device, impedance_spectroscopy_database);
        std::complex<double> exact_impedance    =
            (
                (type.compare("SeriesRC") == 0)
                ?
                series_resistance + 1.0 / std::complex<double>(0.0, capacitance * angular_frequency)
                :
                series_resistance + parallel_resistance / std::complex<double>(1.0, parallel_resistance * capacitance * angular_frequency)
            );
        fout<<boost::format("  %22.15e  %22.15e  %22.15e  %22.15e  %22.15e  %22.15e  %22.15e  %22.15e  %22.15e  \n")
            % frequency
            % computed_impedance.real()
            % computed_impedance.imag()
            % std::abs(computed_impedance)
            % (std::arg(computed_impedance) * 180.0 / pi)
            % exact_impedance.real()
            % exact_impedance.imag()
            % std::abs(exact_impedance)
            % (std::arg(exact_impedance) * 180.0 / pi)
            ;
//          BOOST_CHECK_CLOSE(computed_impedance.real(), exact_impedance.real(), percent_tolerance);
//          BOOST_CHECK_CLOSE(computed_impedance.imag(), exact_impedance.imag(), percent_tolerance);
          BOOST_CHECK_CLOSE(std::abs(computed_impedance), std::abs(exact_impedance), percent_tolerance);
          BOOST_CHECK_CLOSE(std::arg(computed_impedance), std::arg(exact_impedance), percent_tolerance);
    }

}

BOOST_AUTO_TEST_CASE( test_impedance_spectroscopy )
{
    // parse input file
    std::shared_ptr<boost::property_tree::ptree> input_database =
        std::make_shared<boost::property_tree::ptree>();
    read_xml("input_impedance_spectroscopy", *input_database);

    // build an energy storage system
    std::shared_ptr<boost::property_tree::ptree> device_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("device"));
    std::shared_ptr<cap::EnergyStorageDevice> device =
        cap::buildEnergyStorageDevice(std::make_shared<cap::Parameters>(device_database));

    // measure its impedance
    std::fstream fout;
    fout.open("impedance_spectroscopy_data", std::fstream::out);

    std::shared_ptr<boost::property_tree::ptree> impedance_spectroscopy_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("impedance_spectroscopy"));
    cap::impedance_spectroscopy(device, impedance_spectroscopy_database, fout);

}
<commit_msg>removed useless forward declaration<commit_after>#define BOOST_TEST_MODULE TestImpedanceSpectroscopy
#define BOOST_TEST_MAIN
#include <cap/energy_storage_device.h>
#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/test/unit_test.hpp>
#include <gsl/gsl_fft_real.h>
#include <iostream>
#include <fstream>
#include <complex>

namespace cap {

std::complex<double>
measure_impedance(std::shared_ptr<cap::EnergyStorageDevice> dev, std::shared_ptr<boost::property_tree::ptree const> database)
{
    double const frequency       = database->get<double>("frequency"      );
    double const amplitude       = database->get<double>("amplitude"      );
    int    const cycles          = database->get<int   >("cycles"         );
    int    const steps_per_cycle = database->get<int   >("steps_per_cycle");
    double const initial_voltage = 0.0;
    std::vector<int> const powers_of_two =
        { 1, 2 ,4, 8, 16,
          32, 64, 128, 256, 512,
          1024, 2048, 4096, 8192, 16384,
          32768, 65536, 131072, 262144, 524288
        }; // first 20 powers of two
    if (find(powers_of_two.begin(), powers_of_two.end(), (cycles-1)*steps_per_cycle) == powers_of_two.end())
        throw std::runtime_error("(cycles-1)*steps_per_cycle must be a power of two");

    double       time      = 0.0;
    double const time_step = 1.0 / frequency / steps_per_cycle;
    double const phase     = std::asin(initial_voltage / amplitude);
    double const pi        = std::acos(-1.0);
    double const angular_frequency = 2.0 * pi * frequency;
    dev->reset_voltage(initial_voltage);
    double voltage;
    double current;
    std::vector<double> excitation;
    std::vector<double> response;
    for (int n = 0; n < cycles*steps_per_cycle; ++n)
    {
          time += time_step;
          voltage = amplitude * std::sin(angular_frequency * time + phase);
          dev->evolve_one_time_step_changing_voltage(time_step, voltage);
          dev->get_current(current);
          if (n >= steps_per_cycle)
          {
              excitation.push_back(voltage);
              response  .push_back(current);
          }
    }
    gsl_fft_real_radix2_transform(&(excitation[0]), 1, excitation.size());
    gsl_fft_real_radix2_transform(&(response  [0]), 1, response  .size());
    std::complex<double> const impedance =
        std::complex<double>(excitation[(cycles-1)], excitation[excitation.size()-(cycles-1)])
        /
        std::complex<double>(response  [(cycles-1)], response  [response  .size()-(cycles-1)]);
    return impedance;
}

void impedance_spectroscopy(std::shared_ptr<cap::EnergyStorageDevice> dev, std::shared_ptr<boost::property_tree::ptree const> database, std::ostream & os = std::cout)
{
    double const frequency_lower_limit = database->get<double>("frequency_lower_limit");
    double const frequency_upper_limit = database->get<double>("frequency_upper_limit");
    double const ratio                 = database->get<double>("ratio"                );
    double const pi                    = boost::math::constants::pi<double>();
    std::shared_ptr<boost::property_tree::ptree> tmp =
        std::make_shared<boost::property_tree::ptree>(*database);
    for (double frequency = frequency_lower_limit; frequency <= frequency_upper_limit; frequency *= ratio)
    {
        tmp->put("frequency", frequency);
        std::complex<double> impedance =
            measure_impedance(dev, tmp);
        os<<boost::format( "  %20.15e  %20.15e  %20.15e  %20.15e  %20.15e  \n")
            % frequency
            % impedance.real()
            % impedance.imag()
            % std::abs(impedance)
            % (std::arg(impedance) * 180.0 / pi)
            ;
    }
}

} // end namespace cap

BOOST_AUTO_TEST_CASE( test_measure_impedance )
{
    // parse input file
    std::shared_ptr<boost::property_tree::ptree> input_database =
        std::make_shared<boost::property_tree::ptree>();
    read_xml("input_impedance_spectroscopy", *input_database);

    std::string const type = input_database->get<std::string>("device.type");
    // current test will only work for series or parallel rc circuit
    if ((type.compare("SeriesRC") != 0) && (type.compare("ParallelRC") != 0))
        throw std::runtime_error("test measure impedance check not implemented for "+type);

    // build an energy storage system
    std::shared_ptr<boost::property_tree::ptree> device_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("device"));
    std::shared_ptr<cap::EnergyStorageDevice> device =
        cap::buildEnergyStorageDevice(std::make_shared<cap::Parameters>(device_database));

    double const frequency_lower_limit = input_database->get<double>("impedance_spectroscopy.frequency_lower_limit");
    double const frequency_upper_limit = input_database->get<double>("impedance_spectroscopy.frequency_upper_limit");
    double const ratio                 = input_database->get<double>("impedance_spectroscopy.ratio"                );
    double const percent_tolerance     = input_database->get<double>("impedance_spectroscopy.percent_tolerance"    );
    double const series_resistance     = input_database->get<double>("device.series_resistance"                    );
    double const parallel_resistance   = input_database->get<double>("device.parallel_resistance"                  );
    double const capacitance           = input_database->get<double>("device.capacitance"                          );
    double const pi                    = boost::math::constants::pi<double>();

    std::shared_ptr<boost::property_tree::ptree> impedance_spectroscopy_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("impedance_spectroscopy"));
    std::fstream fout("computed_vs_exact_impedance_spectroscopy_data", std::fstream::out);
    for (double frequency = frequency_lower_limit; frequency < frequency_upper_limit; frequency *= ratio)
    {
        double const angular_frequency = 2.0 * pi * frequency;
        impedance_spectroscopy_database->put("frequency", frequency);
        std::complex<double> computed_impedance = cap::measure_impedance(device, impedance_spectroscopy_database);
        std::complex<double> exact_impedance    =
            (
                (type.compare("SeriesRC") == 0)
                ?
                series_resistance + 1.0 / std::complex<double>(0.0, capacitance * angular_frequency)
                :
                series_resistance + parallel_resistance / std::complex<double>(1.0, parallel_resistance * capacitance * angular_frequency)
            );
        fout<<boost::format("  %22.15e  %22.15e  %22.15e  %22.15e  %22.15e  %22.15e  %22.15e  %22.15e  %22.15e  \n")
            % frequency
            % computed_impedance.real()
            % computed_impedance.imag()
            % std::abs(computed_impedance)
            % (std::arg(computed_impedance) * 180.0 / pi)
            % exact_impedance.real()
            % exact_impedance.imag()
            % std::abs(exact_impedance)
            % (std::arg(exact_impedance) * 180.0 / pi)
            ;
//          BOOST_CHECK_CLOSE(computed_impedance.real(), exact_impedance.real(), percent_tolerance);
//          BOOST_CHECK_CLOSE(computed_impedance.imag(), exact_impedance.imag(), percent_tolerance);
          BOOST_CHECK_CLOSE(std::abs(computed_impedance), std::abs(exact_impedance), percent_tolerance);
          BOOST_CHECK_CLOSE(std::arg(computed_impedance), std::arg(exact_impedance), percent_tolerance);
    }

}

BOOST_AUTO_TEST_CASE( test_impedance_spectroscopy )
{
    // parse input file
    std::shared_ptr<boost::property_tree::ptree> input_database =
        std::make_shared<boost::property_tree::ptree>();
    read_xml("input_impedance_spectroscopy", *input_database);

    // build an energy storage system
    std::shared_ptr<boost::property_tree::ptree> device_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("device"));
    std::shared_ptr<cap::EnergyStorageDevice> device =
        cap::buildEnergyStorageDevice(std::make_shared<cap::Parameters>(device_database));

    // measure its impedance
    std::fstream fout;
    fout.open("impedance_spectroscopy_data", std::fstream::out);

    std::shared_ptr<boost::property_tree::ptree> impedance_spectroscopy_database =
        std::make_shared<boost::property_tree::ptree>(input_database->get_child("impedance_spectroscopy"));
    cap::impedance_spectroscopy(device, impedance_spectroscopy_database, fout);

}
<|endoftext|>