<commit_before>// #include "cgal/datatypes/meshes.h"

// #include <boost/algorithm/string/join.hpp>

// #include <possumwood_sdk/node_implementation.h>
// #include <possumwood_sdk/app.h>

// #include <GL/glew.h>
// #include <GL/glu.h>

// #include <ImathVec.h>

// #include "datatypes/vertex_data.inl"

// namespace possumwood {

// template<typename T>
// struct VBOTraits<CGAL::Point_3<CGAL::Simple_cartesian<T>>> {
// 	typedef T element;
// 	static constexpr std::size_t width() { return 3; };
// };

// template<typename T>
// struct VBOTraits<std::vector<T>> {
// 	typedef T element;
// 	static constexpr std::size_t width() { return 1; };
// };

// }

// namespace {

// template<typename T>
// T defaultExtract(const T& val) {
// 	return val;
// }

// template <typename T, typename EXTRACT = std::function<T(const T&)>>
// void addPerPointVBO(possumwood::VertexData& vd, const std::string& name,
//                     const std::string& propertyName, std::size_t triangleCount,
//                     const possumwood::Meshes& mesh,
//                     EXTRACT extract = &defaultExtract<T>) {
// 	vd.addVBO<T>(
// 	    name, triangleCount * 3, possumwood::VertexData::kStatic,
// 	    [mesh, propertyName, extract](possumwood::Buffer<typename possumwood::VBOTraits<T>::element>& buffer, const possumwood::Drawable::ViewportState& vs) {
// 		    std::size_t index = 0;

// 		    for(auto& m : mesh) {
// 			    auto vertProp =
// 			        m.mesh().property_map<possumwood::CGALPolyhedron::Vertex_index, T>(
// 			            propertyName.c_str());

// 			    auto faceProp =
// 			        m.mesh().property_map<possumwood::CGALPolyhedron::Face_index, T>(
// 			            propertyName.c_str());

// 			    // vertex props, handled by polygon-triangle
// 			    if(vertProp.second) {
// 				    for(auto fit = m.mesh().faces_begin(); fit != m.mesh().faces_end();
// 				        ++fit) {
// 					    auto vertices =
// 					        m.mesh().vertices_around_face(m.mesh().halfedge(*fit));

// 					    if(vertices.size() >= 2) {
// 						    auto it = vertices.begin();

// 						    auto val1 = extract(vertProp.first[*it]);
// 						    ++it;

// 						    auto val2 = extract(vertProp.first[*it]);
// 						    ++it;

// 						    while(it != vertices.end()) {
// 							    auto val = extract(vertProp.first[*it]);

// 							    buffer.element(index++) = val1;
// 							    buffer.element(index++) = val2;
// 							    buffer.element(index++) = val;

// 							    ++it;
// 						    }
// 					    }
// 				    }
// 			    }

// 			    // face props, constant for all triangles of a face
// 			    else if(faceProp.second) {
// 				    // iterate over faces
// 				    for(auto fit = m.mesh().faces_begin(); fit != m.mesh().faces_end();
// 				        ++fit) {
// 					    auto vertices =
// 					        m.mesh().vertices_around_face(m.mesh().halfedge(*fit));

// 					    auto n = extract(faceProp.first[*fit]);

// 					    if(vertices.size() >= 2) {
// 						    auto it = vertices.begin();

// 						    ++it;
// 						    ++it;

// 						    while(it != vertices.end()) {
// 							    buffer.element(index++) = n;
// 							    buffer.element(index++) = n;
// 							    buffer.element(index++) = n;

// 							    ++it;
// 						    }
// 					    }
// 				    }
// 			    }
// 			    else
// 				    throw std::runtime_error("Property " + propertyName +
// 				                             " not found as vertex or face property.");
// 		    }

// 		    assert(index == buffer.vertexCount());
// 		});
// }

// struct VBOName {
// 	VBOName() : arraySize(0), recognized(false) {
// 	}

// 	std::string name, type;
// 	std::size_t arraySize;
// 	bool recognized;
// };

// VBOName CGALType(const std::string& t) {
// 	VBOName result;

// 	auto colonPos = t.find(":");
// 	if(colonPos != std::string::npos) {
// 		result.type = t.substr(0, colonPos);
// 		result.name = t.substr(colonPos + 1);
// 		result.arraySize = 1;
// 		result.recognized = true;

// 		assert(colonPos > 0);
// 		if(result.type.back() == ']') {
// 			auto bracketPos = t.find("[");
// 			assert(bracketPos != std::string::npos);

// 			result.arraySize = std::stoi(result.type.substr(
// 			    bracketPos + 1, result.type.length() - bracketPos - 2));
// 			result.type = result.type.substr(0, bracketPos);
// 		}
// 	}

// 	return result;
// }

// using possumwood::Meshes;
// using possumwood::CGALPolyhedron;

// // properties to be skipped during handling - either internal to CGAL, or handled
// // separately
// static const std::set<std::string> skipProperties{
//     {"f:connectivity", "f:removed", "v:connectivity", "v:removed", "v:point"}};

// dependency_graph::OutAttr<std::shared_ptr<const possumwood::VertexData>> a_vd;
// dependency_graph::InAttr<Meshes> a_mesh;

// dependency_graph::State compute(dependency_graph::Values& data) {
// 	dependency_graph::State result;

// 	const Meshes mesh = data.get(a_mesh);

// 	// we're drawing triangles
// 	std::unique_ptr<possumwood::VertexData> vd(new possumwood::VertexData(GL_TRIANGLES));

// 	// first, figure out how many triangles we have
// 	//   there has to be a better way to do this, come on
// 	std::size_t triangleCount = 0;
// 	for(auto& m : mesh)
// 		for(auto it = m.mesh().faces_begin(); it != m.mesh().faces_end(); ++it) {
// 			auto vertices = m.mesh().vertices_around_face(m.mesh().halfedge(*it));

// 			if(vertices.size() > 2)
// 				triangleCount += (vertices.size() - 2);
// 		}

// 	// and build the buffers
// 	if(triangleCount > 0) {
// 		// transfer the position data
// 		addPerPointVBO<possumwood::CGALKernel::Point_3>(*vd, "position", "v:point",
// 		                                                   triangleCount, mesh);

// 		// count the properties - only properties consistent between all meshes can be
// 		// transfered. We don't care about the type of the properties, though - face or
// 		// vertex are both fine
// 		std::map<std::string, std::size_t> propertyCounters;
// 		for(auto& m : mesh) {
// 			auto vertPropList =
// 			    m.mesh().properties<possumwood::CGALPolyhedron::Vertex_index>();
// 			for(auto& vp : vertPropList)
// 				++propertyCounters[vp];

// 			auto facePropList =
// 			    m.mesh().properties<possumwood::CGALPolyhedron::Face_index>();
// 			for(auto& fp : facePropList)
// 				++propertyCounters[fp];
// 		}

// 		// and transfer all properties that are common to all meshes
// 		std::set<std::string> ignoredProperties, inconsistentProperties;
// 		for(auto& pc : propertyCounters)
// 			if(skipProperties.find(pc.first) == skipProperties.end()) {
// 				if(pc.second == mesh.size()) {
// 					// analyse the type
// 					VBOName name = CGALType(pc.first);
// 					if(name.recognized && name.arraySize > 0) {
// 						// yep, the types are hardcoded for now, sorry :(
// 						if(name.type == "vec3" && name.arraySize == 1)
// 							addPerPointVBO<std::array<float, 3>>(
// 							    *vd, name.name, pc.first, triangleCount, mesh);

// 						else if(name.type == "float" && name.arraySize == 1)
// 							addPerPointVBO<float>(*vd, name.name, pc.first,
// 							                         triangleCount, mesh);

// 						else if(name.type == "int" && name.arraySize == 1)
// 							addPerPointVBO<int>(*vd, name.name, pc.first,
// 							                         triangleCount, mesh);

// 						else if(name.type == "float")
// 							for(std::size_t i=0;i<name.arraySize;++i) {
// 								auto fn = [i](const std::vector<float>& v) -> float {
// 									return v[i];
// 								};

// 								addPerPointVBO<std::vector<float>>(
// 								    *vd, name.name + "[" + std::to_string(i) + "]", pc.first, triangleCount, mesh, fn);
// 							}

// 						else if(name.type == "int")
// 							for(std::size_t i=0;i<name.arraySize;++i) {
// 								auto fn = [i](const std::vector<int>& v) -> int {
// 									return v[i];
// 								};

// 								addPerPointVBO<std::vector<int>>(
// 								    *vd, name.name + "[" + std::to_string(i) + "]", pc.first, triangleCount, mesh, fn);
// 							}

// 						else
// 							ignoredProperties.insert(pc.first);
// 					}
// 					else if(pc.second < mesh.size())
// 						ignoredProperties.insert(pc.first);
// 				}
// 				else
// 					inconsistentProperties.insert(pc.first + "(" +
// 					                              std::to_string(pc.second) + "/" +
// 					                              std::to_string(mesh.size()) + ")");
// 			}

// 		if(!inconsistentProperties.empty())
// 			result.addWarning(
// 			    "The following properties were not common to all meshes, and had to be "
// 			    "ignored:\n" +
// 			    boost::algorithm::join(inconsistentProperties, ", "));

// 		if(!ignoredProperties.empty())
// 			result.addWarning("The following property types were not recognized:\n" +
// 			                  boost::algorithm::join(ignoredProperties, ", "));
// 	}

// 	data.set(a_vd, std::shared_ptr<const possumwood::VertexData>(vd.release()));

// 	return result;
// }

// void init(possumwood::Metadata& meta) {
// 	meta.addAttribute(a_vd, "vertex_data");
// 	meta.addAttribute(a_mesh, "mesh");

// 	meta.addInfluence(a_mesh, a_vd);

// 	meta.setCompute(&compute);
// }

// possumwood::NodeImplementation s_impl("render/vertex_data/cgal", init);
// }
<commit_msg>CGAL vertex data source (points only, no properties for now)<commit_after>#include "cgal/datatypes/meshes.h"

#include <boost/algorithm/string/join.hpp>

#include <possumwood_sdk/node_implementation.h>
#include <possumwood_sdk/app.h>

#include <GL/glew.h>
#include <GL/glu.h>

#include <ImathVec.h>

#include "datatypes/vertex_data.inl"

namespace possumwood {

template <typename T>
struct VBOTraits<CGAL::Point_3<CGAL::Simple_cartesian<T>>> {
	typedef T element;
	static constexpr std::size_t width() {
		return 3;
	};
};

template <typename T>
struct VBOTraits<std::vector<T>> {
	typedef T element;
	static constexpr std::size_t width() {
		return 1;
	};
};
}

namespace {

template <typename T>
T defaultExtract(const T& val) {
	return val;
}

void addVerticesVBO(possumwood::VertexData& vd, const possumwood::Meshes& meshes, std::size_t triangleCount) {
	vd.addVBO<possumwood::CGALPolyhedron::Point_3>(
	"position", triangleCount*3, possumwood::VertexData::kStatic,
	[meshes, triangleCount](possumwood::Buffer<typename possumwood::VBOTraits<possumwood::CGALPolyhedron::Point_3>::element>& buffer,
 	        const possumwood::Drawable::ViewportState& vs) {

		// TODO: use index buffer instead
		std::size_t index = 0;

		for(const auto& m : meshes) {
			for(auto fit = m.polyhedron().facets_begin(); fit != m.polyhedron().facets_end(); ++fit)
				if(fit->facet_degree() > 2) {
					auto vit = fit->facet_begin();

					const auto& p1 = vit->vertex()->point();
					++vit;

					const auto& p2 = vit->vertex()->point();
					++vit;

					for(std::size_t v = 2; v < fit->facet_degree(); ++v) {
					    const auto& p = vit->vertex()->point();

					    buffer.element(index++) = p1;
					    buffer.element(index++) = p2;
					    buffer.element(index++) = p;

						++vit;
					}
				}
		}

		assert(index == triangleCount*3);
	});
}

using possumwood::Meshes;
using possumwood::CGALPolyhedron;

dependency_graph::OutAttr<std::shared_ptr<const possumwood::VertexData>> a_vd;
dependency_graph::InAttr<Meshes> a_mesh;

dependency_graph::State compute(dependency_graph::Values& data) {
	dependency_graph::State result;

	const Meshes mesh = data.get(a_mesh);

	// we're drawing triangles
	std::unique_ptr<possumwood::VertexData> vd(new possumwood::VertexData(GL_TRIANGLES));

	// first, figure out how many triangles we have
	//   there has to be a better way to do this, come on
	std::size_t triangleCount = 0;
	for(auto& m : mesh)
		for(auto it = m.polyhedron().facets_begin(); it != m.polyhedron().facets_end(); ++it)
			if(it->facet_degree() > 2)
				triangleCount += (it->facet_degree() - 2);

	// and build the buffers
	if(triangleCount > 0) {
		addVerticesVBO(*vd, mesh, triangleCount);
	}

	data.set(a_vd, std::shared_ptr<const possumwood::VertexData>(vd.release()));

	return result;
}

void init(possumwood::Metadata& meta) {
	meta.addAttribute(a_vd, "vertex_data");
	meta.addAttribute(a_mesh, "mesh");

	meta.addInfluence(a_mesh, a_vd);

	meta.setCompute(&compute);
}

possumwood::NodeImplementation s_impl("render/vertex_data/cgal", init);
}
<|endoftext|>


<commit_before>// Copyright 2016 Connor Taffe

#include <stddef.h>
#include <stdint.h>

#include "src/kernel.h"
#include "src/multiboot.h"
#include "src/result.h"

extern "C" {
[[noreturn]] void _start();
[[noreturn]] void kstart();
}

// boot images
[[gnu::section(".multiboot")]] basilisk::Multiboot header{
    basilisk::Multiboot::kPageAlign | basilisk::Multiboot::kMemInfo |
    basilisk::Multiboot::kVideoInfo};

[[gnu::section(".bootstrap_stack")]] uint8_t stack[16384];

[[gnu::naked]] void _start() {
  asm("movl %0, %%esp\n"
      "call kstart\n" ::"g"(reinterpret_cast<intptr_t>(stack) + sizeof(stack)));
}

void kstart() {
  *reinterpret_cast<uint16_t*>(static_cast<intptr_t>(0xb8000)) = 'A' | 4 << 8;
  basilisk::Kernel::getInstance()->onBoot();
}
<commit_msg>moved stack & header to anonymous namespace<commit_after>// Copyright 2016 Connor Taffe

#include <stddef.h>
#include <stdint.h>

#include "src/kernel.h"
#include "src/multiboot.h"
#include "src/result.h"

extern "C" {
[[noreturn]] void _start();
[[noreturn]] void kstart();
}

namespace {
// boot images
[[gnu::section(".multiboot")]] basilisk::Multiboot header{
    basilisk::Multiboot::kPageAlign | basilisk::Multiboot::kMemInfo |
    basilisk::Multiboot::kVideoInfo};

[[gnu::section(".bootstrap_stack")]] uint8_t stack[16384];
}  // namespace

[[gnu::naked]] void _start() {
  asm("movl %0, %%esp\n"
      "call kstart\n" ::"g"(reinterpret_cast<intptr_t>(stack) + sizeof(stack)));
}

void kstart() {
  *reinterpret_cast<uint16_t*>(static_cast<intptr_t>(0xb8000)) = 'A' | 4 << 8;
  basilisk::Kernel::getInstance()->onBoot();
}
<|endoftext|>


<commit_before><commit_msg>fix for geo test case in ConfigManager<commit_after><|endoftext|>


<commit_before><commit_msg>fixed leak<commit_after><|endoftext|>


<commit_before>/*  This file is part of the Kate project.
 *
 *  Copyright (C) 2010 Christoph Cullmann <cullmann@kde.org>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 */

#include "kateprojectplugin.h"

#include "kateproject.h"
#include "kateprojectconfigpage.h"
#include "kateprojectpluginview.h"

#include <ktexteditor/editor.h>
#include <ktexteditor/application.h>
#include <ktexteditor/document.h>

#include <KSharedConfig>
#include <KConfigGroup>
#include <ThreadWeaver/Queue>

#include <QFileInfo>
#include <QTime>

#include "config.h"

#ifdef HAVE_CTERMID
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#endif

namespace
{
const QString ProjectFileName = QStringLiteral(".kateproject");
const QString GitFolderName = QStringLiteral(".git");
const QString SubversionFolderName = QStringLiteral(".svn");
const QString MercurialFolderName = QStringLiteral(".hg");

const QString GitConfig = QStringLiteral("git");
const QString SubversionConfig = QStringLiteral("subversion");
const QString MercurialConfig = QStringLiteral("mercurial");

const QStringList DefaultConfig = QStringList() << GitConfig << SubversionConfig << MercurialConfig;
}

KateProjectPlugin::KateProjectPlugin(QObject *parent, const QList<QVariant> &)
    : KTextEditor::Plugin(parent)
    , m_completion(this)
    , m_autoGit(true)
    , m_autoSubversion(true)
    , m_autoMercurial(true)
    , m_weaver(new ThreadWeaver::Queue(this))
{
    qRegisterMetaType<KateProjectSharedQStandardItem>("KateProjectSharedQStandardItem");
    qRegisterMetaType<KateProjectSharedQMapStringItem>("KateProjectSharedQMapStringItem");
    qRegisterMetaType<KateProjectSharedProjectIndex>("KateProjectSharedProjectIndex");

    connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentCreated, this, &KateProjectPlugin::slotDocumentCreated);
    connect(&m_fileWatcher, &QFileSystemWatcher::directoryChanged, this, &KateProjectPlugin::slotDirectoryChanged);

#ifdef HAVE_CTERMID
    /**
     * open project for our current working directory, if this kate has a terminal
     * http://stackoverflow.com/questions/1312922/detect-if-stdin-is-a-terminal-or-pipe-in-c-c-qt
     */
    char tty[L_ctermid + 1] = {0};
    ctermid(tty);
    int fd = ::open(tty, O_RDONLY);

    if (fd >= 0) {
        projectForDir(QDir::current());
        ::close(fd);
    }
#endif

    readConfig();

    for (auto document : KTextEditor::Editor::instance()->application()->documents()) {
        slotDocumentCreated(document);
    }
}

KateProjectPlugin::~KateProjectPlugin()
{
    for (KateProject *project : m_projects) {
        m_fileWatcher.removePath(QFileInfo(project->fileName()).canonicalPath());
        delete project;
    }
    m_projects.clear();

    m_weaver->suspend();
    m_weaver->dequeue();
    m_weaver->finish();
    delete m_weaver;
}

QObject *KateProjectPlugin::createView(KTextEditor::MainWindow *mainWindow)
{
    return new KateProjectPluginView(this, mainWindow);
}

int KateProjectPlugin::configPages() const
{
    return 1;
}

KTextEditor::ConfigPage *KateProjectPlugin::configPage(int number, QWidget *parent)
{
    if (number != 0) {
        return nullptr;
    }
    return new KateProjectConfigPage(parent, this);
}

KateProject *KateProjectPlugin::createProjectForFileName(const QString &fileName)
{
    KateProject *project = new KateProject(m_weaver);

    if (!project->loadFromFile(fileName)) {
        delete project;
        return nullptr;
    }

    m_projects.append(project);
    m_fileWatcher.addPath(QFileInfo(fileName).canonicalPath());
    emit projectCreated(project);
    return project;
}

KateProject *KateProjectPlugin::projectForDir(QDir dir)
{
    /**
     * search projects upwards
     * with recursion guard
     */
    QSet<QString> seenDirectories;
    while (!seenDirectories.contains(dir.absolutePath())) {
        /**
         * fill recursion guard
         */
        seenDirectories.insert(dir.absolutePath());

        /**
         * check for project and load it if found
         */
        QString canonicalPath = dir.canonicalPath();
        QString canonicalFileName = dir.filePath(ProjectFileName);

        for (KateProject *project : m_projects) {
            if (project->baseDir() == canonicalPath || project->fileName() == canonicalFileName) {
                return project;
            }
        }

        if (dir.exists(ProjectFileName)) {
            return createProjectForFileName(canonicalFileName);
        }

        KateProject *project;
        if ((project = detectGit(dir)) || (project = detectSubversion(dir)) || (project = detectMercurial(dir))) {
            return project;
        }

        /**
         * else: cd up, if possible or abort
         */
        if (!dir.cdUp()) {
            break;
        }
    }

    return 0;
}

KateProject *KateProjectPlugin::projectForUrl(const QUrl &url)
{
    if (url.isEmpty() || !url.isLocalFile()) {
        return nullptr;
    }

    return projectForDir(QFileInfo(url.toLocalFile()).absoluteDir());
}

void KateProjectPlugin::slotDocumentCreated(KTextEditor::Document *document)
{
    connect(document, &KTextEditor::Document::documentUrlChanged, this, &KateProjectPlugin::slotDocumentUrlChanged);
    connect(document, &KTextEditor::Document::destroyed, this, &KateProjectPlugin::slotDocumentDestroyed);

    slotDocumentUrlChanged(document);
}

void KateProjectPlugin::slotDocumentDestroyed(QObject *document)
{
    if (KateProject *project = m_document2Project.value(document)) {
        project->unregisterDocument(static_cast<KTextEditor::Document *>(document));
    }

    m_document2Project.remove(document);
}

void KateProjectPlugin::slotDocumentUrlChanged(KTextEditor::Document *document)
{
    KateProject *project = projectForUrl(document->url());

    if (KateProject *project = m_document2Project.value(document)) {
        project->unregisterDocument(document);
    }

    if (!project) {
        m_document2Project.remove(document);
    } else {
        m_document2Project[document] = project;
    }

    if (KateProject *project = m_document2Project.value(document)) {
        project->registerDocument(document);
    }
}

void KateProjectPlugin::slotDirectoryChanged(const QString &path)
{
    QString fileName = QDir(path).filePath(ProjectFileName);
    for (KateProject * project : m_projects) {
        if (project->fileName() == fileName) {
            QDateTime lastModified = QFileInfo(fileName).lastModified();
            if (project->fileLastModified().isNull() || (lastModified > project->fileLastModified())) {
                project->reload();
            }
            break;
        }
    }
}

KateProject* KateProjectPlugin::detectGit(const QDir &dir)
{

    if (m_autoGit && dir.exists(GitFolderName) && QFileInfo(dir, GitFolderName).isDir()) {
        return createProjectForRepository(QStringLiteral("git"), dir);
    }

    return nullptr;
}

KateProject* KateProjectPlugin::detectSubversion(const QDir &dir)
{
    if (m_autoSubversion && dir.exists(SubversionFolderName) && QFileInfo(dir, SubversionFolderName).isDir()) {
        return createProjectForRepository(QStringLiteral("svn"), dir);
    }

    return nullptr;
}

KateProject* KateProjectPlugin::detectMercurial(const QDir &dir)
{
    if (m_autoMercurial && dir.exists(MercurialFolderName) && QFileInfo(dir, MercurialFolderName).isDir()) {
        return createProjectForRepository(QStringLiteral("hg"), dir);
    }

    return nullptr;
}

KateProject *KateProjectPlugin::createProjectForRepository(const QString &type, const QDir &dir)
{
    QVariantMap cnf, files;
    files[type] = 1;
    cnf[QLatin1String("name")] = dir.dirName();
    cnf[QLatin1String("files")] = (QVariantList() << files);

    KateProject *project = new KateProject(m_weaver);
    project->loadFromData(cnf, dir.canonicalPath());

    m_projects.append(project);

    emit projectCreated(project);
    return project;
}

void KateProjectPlugin::setAutoRepository(bool onGit, bool onSubversion, bool onMercurial)
{
    m_autoGit = onGit;
    m_autoSubversion = onSubversion;
    m_autoMercurial = onMercurial;
    writeConfig();
}

bool KateProjectPlugin::autoGit() const
{
    return m_autoGit;
}

bool KateProjectPlugin::autoSubversion() const
{
    return m_autoSubversion;
}

bool KateProjectPlugin::autoMercurial() const
{
    return m_autoMercurial;
}

void KateProjectPlugin::readConfig()
{
    KConfigGroup config(KSharedConfig::openConfig(), "project");
    QStringList autorepository = config.readEntry("autorepository", DefaultConfig);

    m_autoGit = m_autoSubversion = m_autoMercurial = false;

    if (autorepository.contains(GitConfig)) {
        m_autoGit = true;
    }

    if (autorepository.contains(SubversionConfig)) {
        m_autoSubversion = true;
    }

    if (autorepository.contains(MercurialConfig)) {
        m_autoMercurial = true;
    }
}

void KateProjectPlugin::writeConfig()
{
    KConfigGroup config(KSharedConfig::openConfig(), "project");
    QStringList repos;

    if (m_autoGit) {
        repos << GitConfig;
    }

    if (m_autoSubversion) {
        repos << SubversionConfig;
    }

    if (m_autoMercurial) {
        repos << MercurialConfig;
    }

    config.writeEntry("autorepository", repos);
}
<commit_msg>try to fix shutdown crash BUG: 346911<commit_after>/*  This file is part of the Kate project.
 *
 *  Copyright (C) 2010 Christoph Cullmann <cullmann@kde.org>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 */

#include "kateprojectplugin.h"

#include "kateproject.h"
#include "kateprojectconfigpage.h"
#include "kateprojectpluginview.h"

#include <ktexteditor/editor.h>
#include <ktexteditor/application.h>
#include <ktexteditor/document.h>

#include <KSharedConfig>
#include <KConfigGroup>
#include <ThreadWeaver/Queue>

#include <QFileInfo>
#include <QTime>

#include "config.h"

#ifdef HAVE_CTERMID
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#endif

namespace
{
const QString ProjectFileName = QStringLiteral(".kateproject");
const QString GitFolderName = QStringLiteral(".git");
const QString SubversionFolderName = QStringLiteral(".svn");
const QString MercurialFolderName = QStringLiteral(".hg");

const QString GitConfig = QStringLiteral("git");
const QString SubversionConfig = QStringLiteral("subversion");
const QString MercurialConfig = QStringLiteral("mercurial");

const QStringList DefaultConfig = QStringList() << GitConfig << SubversionConfig << MercurialConfig;
}

KateProjectPlugin::KateProjectPlugin(QObject *parent, const QList<QVariant> &)
    : KTextEditor::Plugin(parent)
    , m_completion(this)
    , m_autoGit(true)
    , m_autoSubversion(true)
    , m_autoMercurial(true)
    , m_weaver(new ThreadWeaver::Queue(this))
{
    qRegisterMetaType<KateProjectSharedQStandardItem>("KateProjectSharedQStandardItem");
    qRegisterMetaType<KateProjectSharedQMapStringItem>("KateProjectSharedQMapStringItem");
    qRegisterMetaType<KateProjectSharedProjectIndex>("KateProjectSharedProjectIndex");

    connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentCreated, this, &KateProjectPlugin::slotDocumentCreated);
    connect(&m_fileWatcher, &QFileSystemWatcher::directoryChanged, this, &KateProjectPlugin::slotDirectoryChanged);

#ifdef HAVE_CTERMID
    /**
     * open project for our current working directory, if this kate has a terminal
     * http://stackoverflow.com/questions/1312922/detect-if-stdin-is-a-terminal-or-pipe-in-c-c-qt
     */
    char tty[L_ctermid + 1] = {0};
    ctermid(tty);
    int fd = ::open(tty, O_RDONLY);

    if (fd >= 0) {
        projectForDir(QDir::current());
        ::close(fd);
    }
#endif

    readConfig();

    for (auto document : KTextEditor::Editor::instance()->application()->documents()) {
        slotDocumentCreated(document);
    }
}

KateProjectPlugin::~KateProjectPlugin()
{
    for (KateProject *project : m_projects) {
        m_fileWatcher.removePath(QFileInfo(project->fileName()).canonicalPath());
        delete project;
    }
    m_projects.clear();

    m_weaver->shutDown();
    delete m_weaver;
}

QObject *KateProjectPlugin::createView(KTextEditor::MainWindow *mainWindow)
{
    return new KateProjectPluginView(this, mainWindow);
}

int KateProjectPlugin::configPages() const
{
    return 1;
}

KTextEditor::ConfigPage *KateProjectPlugin::configPage(int number, QWidget *parent)
{
    if (number != 0) {
        return nullptr;
    }
    return new KateProjectConfigPage(parent, this);
}

KateProject *KateProjectPlugin::createProjectForFileName(const QString &fileName)
{
    KateProject *project = new KateProject(m_weaver);

    if (!project->loadFromFile(fileName)) {
        delete project;
        return nullptr;
    }

    m_projects.append(project);
    m_fileWatcher.addPath(QFileInfo(fileName).canonicalPath());
    emit projectCreated(project);
    return project;
}

KateProject *KateProjectPlugin::projectForDir(QDir dir)
{
    /**
     * search projects upwards
     * with recursion guard
     */
    QSet<QString> seenDirectories;
    while (!seenDirectories.contains(dir.absolutePath())) {
        /**
         * fill recursion guard
         */
        seenDirectories.insert(dir.absolutePath());

        /**
         * check for project and load it if found
         */
        QString canonicalPath = dir.canonicalPath();
        QString canonicalFileName = dir.filePath(ProjectFileName);

        for (KateProject *project : m_projects) {
            if (project->baseDir() == canonicalPath || project->fileName() == canonicalFileName) {
                return project;
            }
        }

        if (dir.exists(ProjectFileName)) {
            return createProjectForFileName(canonicalFileName);
        }

        KateProject *project;
        if ((project = detectGit(dir)) || (project = detectSubversion(dir)) || (project = detectMercurial(dir))) {
            return project;
        }

        /**
         * else: cd up, if possible or abort
         */
        if (!dir.cdUp()) {
            break;
        }
    }

    return 0;
}

KateProject *KateProjectPlugin::projectForUrl(const QUrl &url)
{
    if (url.isEmpty() || !url.isLocalFile()) {
        return nullptr;
    }

    return projectForDir(QFileInfo(url.toLocalFile()).absoluteDir());
}

void KateProjectPlugin::slotDocumentCreated(KTextEditor::Document *document)
{
    connect(document, &KTextEditor::Document::documentUrlChanged, this, &KateProjectPlugin::slotDocumentUrlChanged);
    connect(document, &KTextEditor::Document::destroyed, this, &KateProjectPlugin::slotDocumentDestroyed);

    slotDocumentUrlChanged(document);
}

void KateProjectPlugin::slotDocumentDestroyed(QObject *document)
{
    if (KateProject *project = m_document2Project.value(document)) {
        project->unregisterDocument(static_cast<KTextEditor::Document *>(document));
    }

    m_document2Project.remove(document);
}

void KateProjectPlugin::slotDocumentUrlChanged(KTextEditor::Document *document)
{
    KateProject *project = projectForUrl(document->url());

    if (KateProject *project = m_document2Project.value(document)) {
        project->unregisterDocument(document);
    }

    if (!project) {
        m_document2Project.remove(document);
    } else {
        m_document2Project[document] = project;
    }

    if (KateProject *project = m_document2Project.value(document)) {
        project->registerDocument(document);
    }
}

void KateProjectPlugin::slotDirectoryChanged(const QString &path)
{
    QString fileName = QDir(path).filePath(ProjectFileName);
    for (KateProject * project : m_projects) {
        if (project->fileName() == fileName) {
            QDateTime lastModified = QFileInfo(fileName).lastModified();
            if (project->fileLastModified().isNull() || (lastModified > project->fileLastModified())) {
                project->reload();
            }
            break;
        }
    }
}

KateProject* KateProjectPlugin::detectGit(const QDir &dir)
{

    if (m_autoGit && dir.exists(GitFolderName) && QFileInfo(dir, GitFolderName).isDir()) {
        return createProjectForRepository(QStringLiteral("git"), dir);
    }

    return nullptr;
}

KateProject* KateProjectPlugin::detectSubversion(const QDir &dir)
{
    if (m_autoSubversion && dir.exists(SubversionFolderName) && QFileInfo(dir, SubversionFolderName).isDir()) {
        return createProjectForRepository(QStringLiteral("svn"), dir);
    }

    return nullptr;
}

KateProject* KateProjectPlugin::detectMercurial(const QDir &dir)
{
    if (m_autoMercurial && dir.exists(MercurialFolderName) && QFileInfo(dir, MercurialFolderName).isDir()) {
        return createProjectForRepository(QStringLiteral("hg"), dir);
    }

    return nullptr;
}

KateProject *KateProjectPlugin::createProjectForRepository(const QString &type, const QDir &dir)
{
    QVariantMap cnf, files;
    files[type] = 1;
    cnf[QLatin1String("name")] = dir.dirName();
    cnf[QLatin1String("files")] = (QVariantList() << files);

    KateProject *project = new KateProject(m_weaver);
    project->loadFromData(cnf, dir.canonicalPath());

    m_projects.append(project);

    emit projectCreated(project);
    return project;
}

void KateProjectPlugin::setAutoRepository(bool onGit, bool onSubversion, bool onMercurial)
{
    m_autoGit = onGit;
    m_autoSubversion = onSubversion;
    m_autoMercurial = onMercurial;
    writeConfig();
}

bool KateProjectPlugin::autoGit() const
{
    return m_autoGit;
}

bool KateProjectPlugin::autoSubversion() const
{
    return m_autoSubversion;
}

bool KateProjectPlugin::autoMercurial() const
{
    return m_autoMercurial;
}

void KateProjectPlugin::readConfig()
{
    KConfigGroup config(KSharedConfig::openConfig(), "project");
    QStringList autorepository = config.readEntry("autorepository", DefaultConfig);

    m_autoGit = m_autoSubversion = m_autoMercurial = false;

    if (autorepository.contains(GitConfig)) {
        m_autoGit = true;
    }

    if (autorepository.contains(SubversionConfig)) {
        m_autoSubversion = true;
    }

    if (autorepository.contains(MercurialConfig)) {
        m_autoMercurial = true;
    }
}

void KateProjectPlugin::writeConfig()
{
    KConfigGroup config(KSharedConfig::openConfig(), "project");
    QStringList repos;

    if (m_autoGit) {
        repos << GitConfig;
    }

    if (m_autoSubversion) {
        repos << SubversionConfig;
    }

    if (m_autoMercurial) {
        repos << MercurialConfig;
    }

    config.writeEntry("autorepository", repos);
}
<|endoftext|>


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

#include "utils/linearAlg2D.h" //Distance from point to line.
#include "MergeInfillLines.h"

namespace cura
{

    MergeInfillLines::MergeInfillLines(ExtruderPlan& plan) : extruder_plan(plan)
    {
        //Just copy the parameters to their fields.
    }

    void MergeInfillLines::mergeLinesSharedEndStartPoint(GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start) const
    {
        for (const Point second_path_point : second_path.points)
        {
            first_path.points.push_back(second_path_point); //Move the coordinates over to the first path.
        }
    }

    void MergeInfillLines::mergeLinesSideBySide(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start) const
    {
        coord_t first_path_length_flow = 0;
        Point average_first_path;

        Point previous_point = first_path_start;
        for (const Point point : first_path.points)
        {
            first_path_length_flow += vSize(point - previous_point);
            previous_point = point;
        }
        first_path_length_flow *= first_path.flow; //To get the volume we don't need to include the line width since it's the same for both lines.

        if (first_is_already_merged)
        {
            // take second point of path, first_path.points[0]
            average_first_path = first_path.points[0];
        }
        else
        {
            average_first_path += first_path_start;
            for (const Point point : first_path.points)
            {
                average_first_path += point;
            }
            average_first_path /= (first_path.points.size() + 1);
        }

        coord_t second_path_length_flow = 0;
        Point previous_point_second = second_path_start;
        Point average_second_path = second_path_start;
        for (const Point point : second_path.points)
        {
            second_path_length_flow += vSize(point - previous_point_second);
            average_second_path += point;
            previous_point_second = point;
        }
        second_path_length_flow *= second_path.flow;
        average_second_path /= (second_path.points.size() + 1);

        coord_t new_path_length = 0;

        if (first_is_already_merged) {
            // check if the new point is a good extension of last part of existing polyline
            if (LinearAlg2D::getDist2FromLine(average_second_path, first_path.points[first_path.points.size()-2], first_path.points[first_path.points.size()-1]) == 0) {
                // replace last point with new point if it's an extension
                first_path.points[first_path.points.size()-1] = average_second_path;
            } else {
                first_path.points.push_back(average_second_path);
            }
        } else {
            first_path.points.clear();
            first_path.points.push_back(average_first_path);
            first_path.points.push_back(average_second_path);
        }
        previous_point = first_path_start;
        for (const Point point : first_path.points)
        {
            new_path_length += vSize(point - previous_point);
            previous_point = point;
        }

        first_path.flow = static_cast<double>(first_path_length_flow + second_path_length_flow) / new_path_length;
    }

    bool MergeInfillLines::tryMerge(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, Point second_path_start) const
    {
        if (first_path.config->isTravelPath()) //Don't merge travel moves.
        {
            return false;
        }
        if (first_path.config != second_path.config) //Only merge lines that have the same type.
        {
            return false;
        }
        if (first_path.config->type != PrintFeatureType::Infill && first_path.config->type != PrintFeatureType::Skin) //Only merge skin and infill lines.
        {
            return false;
        }
        if ((!first_is_already_merged && first_path.points.size() > 1) || second_path.points.size() > 1)
        {
            // For now we only merge simple lines, not polylines, to keep it simple.
            // If the first line is already a merged line, then allow it.
            return false;
        }

        const Point first_path_end = first_path.points.back();
        Point second_path_end = second_path.points.back();
        const Point first_direction = first_path_end - first_path_start;
        Point second_direction = second_path_end - second_path_start;
        coord_t dot_product = dot(first_direction, second_direction);
        const coord_t first_size = vSize(first_direction);
        const coord_t second_size = vSize(second_direction);
    //    if (dot_product < 0) //Make lines in the same direction by flipping one.
    //    {
    //        second_direction *= -1;
    //        dot_product *= -1;
    //        Point swap = second_path_end;
    //        second_path_end = second_path_start;
    //        second_path_start = swap;
    //    }

        //Check if lines are connected end-to-end and can be merged that way.
        const coord_t line_width = first_path.config->getLineWidth();
        if (vSize2(first_path_end - second_path_start) < line_width * line_width || vSize2(first_path_start - second_path_end) < line_width * line_width) //Paths are already (practically) connected, end-to-end.
        {
            //Only merge if lines are more or less in the same direction.
            const bool is_straight = dot_product + 400 > first_size * second_size; //400 = 20*20, where 20 micron is the allowed inaccuracy in the dot product, allowing a slight curve.
            if (is_straight) {
                mergeLinesSharedEndStartPoint(first_path, first_path_start, second_path, second_path_start);
                return true;
            }
        }

        //Lines may be adjacent side-by-side then.
        Point first_path_middle;
        coord_t merged_size2;
        if (first_is_already_merged) {
            first_path_middle = first_path.points[0];  // the second point here was once the "middle"
        } else {
            first_path_middle = (first_path_start + first_path_end) / 2;
        }
        const Point second_path_middle = (second_path_start + second_path_end) / 2;
        const Point merged_direction = second_path_middle - first_path_middle;
        if (first_is_already_merged)
        {
            merged_size2 = vSize2(second_path_middle - first_path.points.back());  // check distance with last point in merged line that is to be replaced
        }
        else
        {
            merged_size2 = vSize2(merged_direction);
        }
        if (merged_size2 > 25 * line_width * line_width)
        {
            return false; //Lines are too far away from each other.
        }
        if (LinearAlg2D::getDist2FromLine(first_path_start,  second_path_middle, second_path_middle + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(first_path_end,    second_path_middle, second_path_middle + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_start, first_path_middle,  first_path_middle  + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_end,   first_path_middle,  first_path_middle  + merged_direction) > 4 * line_width * line_width)
        {
            return false; //One of the lines is too far from the merged line. Lines would be too wide or too far off.
        }

        mergeLinesSideBySide(first_is_already_merged, first_path, first_path_start, second_path, second_path_start);
        return true;
    }

    bool MergeInfillLines::mergeInfillLines(std::vector<GCodePath>& paths, const Point starting_position) const
    {
        /* Algorithm overview:
            1. Loop over all lines to see if they can be merged.
            1a. Check if two adjacent lines can be merged (skipping travel moves in
                between).
            1b. If they can, merge both lines into the first line.
            1c. If they are merged, check next that the first line can be merged
                with the line after the second line.
            2. Do a second iteration over all paths to remove the tombstones. */
        std::vector<size_t> remove_path_indices;
        std::set<size_t> is_merged;
        std::set<size_t> removed;  // keep track of what we already removed, so don't remove it again

        //For each two adjacent lines, see if they can be merged.
        size_t first_path_index = 0;
        Point first_path_start = starting_position;
        size_t second_path_index = 1;

        for (; second_path_index < paths.size(); second_path_index++)
        {
            GCodePath& first_path = paths[first_path_index];
            GCodePath& second_path = paths[second_path_index];
            Point second_path_start = paths[second_path_index - 1].points.back();
            if (second_path.config->isTravelPath())
            {
                continue; //Skip travel paths.
            }

            if (tryMerge(is_merged.find(first_path_index) != is_merged.end(), first_path, first_path_start, second_path, second_path_start))
            {
                /* If we combine two lines, the next path may also be merged into the fist line, so we do NOT update
                first_path_index. */
                for (size_t to_delete_index = first_path_index + 1; to_delete_index <= second_path_index; to_delete_index++)
                {
                    if (removed.find(to_delete_index) == removed.end())  // if there are line(s) between first and second, then those lines are already marked as to be deleted, only add the new line(s)
                    {
                        remove_path_indices.push_back(to_delete_index);
                        removed.insert(to_delete_index);
                    }
                }
                is_merged.insert(first_path_index);
            }
            else
            {
                /* If we do not combine, the next iteration we must simply merge the
                second path with the line after it. */
                first_path_index = second_path_index;
                first_path_start = second_path_start;
            }
        }

        //Delete all removed lines in one pass so that we need to move lines less often.
        if (!remove_path_indices.empty())
        {
            size_t path_index = remove_path_indices[0];
            for (size_t removed_position = 1; removed_position < remove_path_indices.size(); removed_position++)
            {
                for (; path_index < remove_path_indices[removed_position] - removed_position; path_index++)
                {
                    paths[path_index] = paths[path_index + removed_position]; //Shift all paths.
                }
            }
            for (; path_index < paths.size() - remove_path_indices.size(); path_index++) //Remaining shifts at the end.
            {
                paths[path_index] = paths[path_index + remove_path_indices.size()];
            }
            paths.erase(paths.begin() + path_index, paths.end());
            return true;
        }
        else
        {
            return false;
        }
    }
}//namespace cura
<commit_msg>Restrict length, better good merge result prediction, renamed a few variables. Working pretty good now. CURA-5535<commit_after>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "utils/linearAlg2D.h" //Distance from point to line.
#include "MergeInfillLines.h"

namespace cura
{

    MergeInfillLines::MergeInfillLines(ExtruderPlan& plan) : extruder_plan(plan)
    {
        //Just copy the parameters to their fields.
    }

    void MergeInfillLines::mergeLinesSharedEndStartPoint(GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start) const
    {
        for (const Point second_path_point : second_path.points)
        {
            first_path.points.push_back(second_path_point); //Move the coordinates over to the first path.
        }
    }

    void MergeInfillLines::mergeLinesSideBySide(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start) const
    {
        coord_t first_path_length_flow = 0;
        Point average_first_path;

        Point previous_point = first_path_start;
        for (const Point point : first_path.points)
        {
            first_path_length_flow += vSize(point - previous_point);
            previous_point = point;
        }
        first_path_length_flow *= first_path.flow; //To get the volume we don't need to include the line width since it's the same for both lines.

        if (first_is_already_merged)
        {
            // take second point of path, first_path.points[0]
            average_first_path = first_path.points[0];
        }
        else
        {
            average_first_path += first_path_start;
            for (const Point point : first_path.points)
            {
                average_first_path += point;
            }
            average_first_path /= (first_path.points.size() + 1);
        }

        coord_t second_path_length_flow = 0;
        Point previous_point_second = second_path_start;
        Point average_second_path = second_path_start;
        for (const Point point : second_path.points)
        {
            second_path_length_flow += vSize(point - previous_point_second);
            average_second_path += point;
            previous_point_second = point;
        }
        second_path_length_flow *= second_path.flow;
        average_second_path /= (second_path.points.size() + 1);

        coord_t new_path_length = 0;

        if (first_is_already_merged)
        {
            // check if the new point is a good extension of last part of existing polyline
            // because of potential accumulation of errors introduced each time a line is merged, we do not allow any error.
            if (first_path.points.size() > 1 && LinearAlg2D::getDist2FromLine(average_second_path, first_path.points[first_path.points.size()-2], first_path.points[first_path.points.size()-1]) == 0) {
                first_path.points[first_path.points.size()-1] = average_second_path;
            } else {
                first_path.points.push_back(average_second_path);
            }
        }
        else
        {
            first_path.points.clear();
            first_path.points.push_back(average_first_path);
            first_path.points.push_back(average_second_path);
        }
        previous_point = first_path_start;
        for (const Point point : first_path.points)
        {
            new_path_length += vSize(point - previous_point);
            previous_point = point;
        }

        first_path.flow = static_cast<double>(first_path_length_flow + second_path_length_flow) / new_path_length;
    }

    bool MergeInfillLines::tryMerge(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, Point second_path_start) const
    {
        if (first_path.config->isTravelPath()) //Don't merge travel moves.
        {
            return false;
        }
        if (first_path.config != second_path.config) //Only merge lines that have the same type.
        {
            return false;
        }
        if (first_path.config->type != PrintFeatureType::Infill && first_path.config->type != PrintFeatureType::Skin) //Only merge skin and infill lines.
        {
            return false;
        }
        if ((!first_is_already_merged && first_path.points.size() > 1) || second_path.points.size() > 1)
        {
            // For now we only merge simple lines, not polylines, to keep it simple.
            // If the first line is already a merged line, then allow it.
            return false;
        }

        const Point first_path_end = first_path.points.back();
        const Point second_path_end = second_path.points.back();
        const Point first_direction = first_path_end - first_path_start;
        const Point second_direction = second_path_end - second_path_start;
        const coord_t dot_product = dot(first_direction, second_direction);
        const coord_t first_size = vSize(first_direction);  // it's an estimate if first_is_already_merged as it may contain more points, but we're mostly going one direction
        const coord_t second_size = vSize(second_direction);
        const coord_t line_width = first_path.config->getLineWidth();
        // restrict length
        if (!first_is_already_merged && first_size > 3 * line_width)
        {
            return false;
        }
        if (second_size > 3 * line_width)
        {
            return false;
        }

        //Check if lines are connected end-to-end and can be merged that way.
        if (vSize2(first_path_end - second_path_start) < line_width * line_width || vSize2(first_path_start - second_path_end) < line_width * line_width) //Paths are already (practically) connected, end-to-end.
        {
            //Only merge if lines are more or less in the same direction.
            const bool is_straight = dot_product + 400 > first_size * second_size; //400 = 20*20, where 20 micron is the allowed inaccuracy in the dot product, allowing a slight curve.
            if (is_straight) {
                mergeLinesSharedEndStartPoint(first_path, first_path_start, second_path, second_path_start);
                return true;
            }
        }

        //Lines may be adjacent side-by-side then.
        Point first_path_leave_point;
        coord_t merged_size2;
        if (first_is_already_merged) {
            first_path_leave_point = first_path.points.back();  // this is the point that's going to merge
        } else {
            first_path_leave_point = (first_path_start + first_path_end) / 2;
        }
        const Point second_path_destination_point = (second_path_start + second_path_end) / 2;
        const Point merged_direction = second_path_destination_point - first_path_leave_point;
        if (first_is_already_merged)
        {
            merged_size2 = vSize2(second_path_destination_point - first_path.points.back());  // check distance with last point in merged line that is to be replaced
        }
        else
        {
            merged_size2 = vSize2(merged_direction);
        }
        if (merged_size2 > 25 * line_width * line_width)
        {
            return false; //Lines are too far away from each other.
        }
        if (LinearAlg2D::getDist2FromLine(first_path_start,  second_path_destination_point, second_path_destination_point + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(first_path_end, second_path_destination_point, second_path_destination_point + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_start, first_path_leave_point, first_path_leave_point + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_end,   first_path_leave_point, first_path_leave_point + merged_direction) > 4 * line_width * line_width)
        {
            return false; //One of the lines is too far from the merged line. Lines would be too wide or too far off.
        }
        if (first_is_already_merged && first_path.points.size() > 1 && first_path.points[first_path.points.size() - 2] == second_path_destination_point)  // yes this can actually happen
        {
            return false;
        }

        mergeLinesSideBySide(first_is_already_merged, first_path, first_path_start, second_path, second_path_start);
        return true;
    }

    bool MergeInfillLines::mergeInfillLines(std::vector<GCodePath>& paths, const Point starting_position) const
    {
        /* Algorithm overview:
            1. Loop over all lines to see if they can be merged.
            1a. Check if two adjacent lines can be merged (skipping travel moves in
                between).
            1b. If they can, merge both lines into the first line.
            1c. If they are merged, check next that the first line can be merged
                with the line after the second line.
            2. Do a second iteration over all paths to remove the tombstones. */
        std::vector<size_t> remove_path_indices;
        std::set<size_t> is_merged;
        std::set<size_t> removed;  // keep track of what we already removed, so don't remove it again

        //For each two adjacent lines, see if they can be merged.
        size_t first_path_index = 0;
        Point first_path_start = starting_position;
        size_t second_path_index = 1;

        for (; second_path_index < paths.size(); second_path_index++)
        {
            GCodePath& first_path = paths[first_path_index];
            GCodePath& second_path = paths[second_path_index];
            Point second_path_start = paths[second_path_index - 1].points.back();
            if (second_path.config->isTravelPath())
            {
                continue; //Skip travel paths.
            }

            if (tryMerge(is_merged.find(first_path_index) != is_merged.end(), first_path, first_path_start, second_path, second_path_start))
            {
                /* If we combine two lines, the next path may also be merged into the fist line, so we do NOT update
                first_path_index. */
                for (size_t to_delete_index = first_path_index + 1; to_delete_index <= second_path_index; to_delete_index++)
                {
                    if (removed.find(to_delete_index) == removed.end())  // if there are line(s) between first and second, then those lines are already marked as to be deleted, only add the new line(s)
                    {
                        remove_path_indices.push_back(to_delete_index);
                        removed.insert(to_delete_index);
                    }
                }
                is_merged.insert(first_path_index);
            }
            else
            {
                /* If we do not combine, the next iteration we must simply merge the
                second path with the line after it. */
                first_path_index = second_path_index;
                first_path_start = second_path_start;
            }
        }

        //Delete all removed lines in one pass so that we need to move lines less often.
        if (!remove_path_indices.empty())
        {
            size_t path_index = remove_path_indices[0];
            for (size_t removed_position = 1; removed_position < remove_path_indices.size(); removed_position++)
            {
                for (; path_index < remove_path_indices[removed_position] - removed_position; path_index++)
                {
                    paths[path_index] = paths[path_index + removed_position]; //Shift all paths.
                }
            }
            for (; path_index < paths.size() - remove_path_indices.size(); path_index++) //Remaining shifts at the end.
            {
                paths[path_index] = paths[path_index + remove_path_indices.size()];
            }
            paths.erase(paths.begin() + path_index, paths.end());
            return true;
        }
        else
        {
            return false;
        }
    }
}//namespace cura
<|endoftext|>


<commit_before>//
// Copyright (c) 2013 Christoph Malek
// See LICENSE for more information.
//

#include <mlk/network/network.h>

#include <iostream>

int main()
{
	// create a udp socket
	mlk::ntw::sock<mlk::ntw::sock_type::udp, false> udp_sock; // the boolean sets blocking mode(true) or non-blocking mode(false)
	mlk::ntw::ip_address to_addr{"my_address.com:my_port"}; // <- this will look up the ip from host 'my_address.com'
	// possible alternative: addr{"192.168.1.1, 80, false"}; <- this will NOT look up the ip address
	mlk::data_packet data{'r', 'e', 'q', 'u', 'e', 's', 't'};

	udp_sock.send(to_addr, data); // send data to host

	mlk::ntw::ip_address from_addr;
	udp_sock.recv(from_addr, data, 1024); // better: loop this recv when mode is non-blocking

	if(!udp_sock.error())
		std::cout << data.data() << std::endl; // display the got data response

	// TCP isnt implemented yet
}
<commit_msg>added socket aliases to tests_netowrk.cpp<commit_after>//
// Copyright (c) 2013 Christoph Malek
// See LICENSE for more information.
//

#include <mlk/network/network.h>

#include <iostream>

int main()
{
    mlk::ntw::udp_sock<true> udp_sock_alias; // create a blocking udp socket (alias)
    mlk::ntw::tcp_sock<false> tcp_sock_alias; // create a non-blocking tcp socket (alias)

	// create a udp socket
	mlk::ntw::sock<mlk::ntw::sock_type::udp, false> udp_sock; // the boolean sets blocking mode(true) or non-blocking mode(false)
	mlk::ntw::ip_address to_addr{"my_address.com:my_port"}; // <- this will look up the ip from host 'my_address.com'
	// possible alternative: addr{"192.168.1.1, 80, false"}; <- this will NOT look up the ip address
	mlk::data_packet data{'r', 'e', 'q', 'u', 'e', 's', 't'};

	udp_sock.send(to_addr, data); // send data to host

	mlk::ntw::ip_address from_addr;
	udp_sock.recv(from_addr, data, 1024); // better: loop this recv when mode is non-blocking

	if(!udp_sock.error())
		std::cout << data.data() << std::endl; // display the got data response

	// TCP isnt implemented yet
}
<|endoftext|>


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

#include "utils/linearAlg2D.h" //Distance from point to line.
#include "MergeInfillLines.h"

namespace cura
{

    MergeInfillLines::MergeInfillLines(ExtruderPlan& plan) : extruder_plan(plan)
    {
        //Just copy the parameters to their fields.
    }

    void MergeInfillLines::mergeLinesSharedEndStartPoint(GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start) const
    {
        for (const Point second_path_point : second_path.points)
        {
            first_path.points.push_back(second_path_point); //Move the coordinates over to the first path.
        }
    }

    void MergeInfillLines::mergeLinesSideBySide(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start) const
    {
        coord_t first_path_length_flow = 0;
        Point average_first_path;

        Point previous_point = first_path_start;
        for (const Point point : first_path.points)
        {
            first_path_length_flow += vSize(point - previous_point);
            previous_point = point;
        }
        first_path_length_flow *= first_path.flow; //To get the volume we don't need to include the line width since it's the same for both lines.

        if (first_is_already_merged)
        {
            // take second point of path, first_path.points[0]
            average_first_path = first_path.points[0];
        }
        else
        {
            average_first_path += first_path_start;
            for (const Point point : first_path.points)
            {
                average_first_path += point;
            }
            average_first_path /= (first_path.points.size() + 1);
        }

        coord_t second_path_length_flow = 0;
        Point previous_point_second = second_path_start;
        Point average_second_path = second_path_start;
        for (const Point point : second_path.points)
        {
            second_path_length_flow += vSize(point - previous_point_second);
            average_second_path += point;
            previous_point_second = point;
        }
        second_path_length_flow *= second_path.flow;
        average_second_path /= (second_path.points.size() + 1);

        coord_t new_path_length = 0;

        if (first_is_already_merged)
        {
            // check if the new point is a good extension of last part of existing polyline
            // because of potential accumulation of errors introduced each time a line is merged, we do not allow any error.
            if (first_path.points.size() > 1 && LinearAlg2D::getDist2FromLine(average_second_path, first_path.points[first_path.points.size()-2], first_path.points[first_path.points.size()-1]) == 0) {
                first_path.points[first_path.points.size()-1] = average_second_path;
            } else {
                first_path.points.push_back(average_second_path);
            }
        }
        else
        {
            first_path.points.clear();
            first_path.points.push_back(average_first_path);
            first_path.points.push_back(average_second_path);
        }
        previous_point = first_path_start;
        for (const Point point : first_path.points)
        {
            new_path_length += vSize(point - previous_point);
            previous_point = point;
        }

        first_path.flow = static_cast<double>(first_path_length_flow + second_path_length_flow) / new_path_length;
    }

    bool MergeInfillLines::tryMerge(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, Point second_path_start) const
    {
        if (first_path.config->isTravelPath()) //Don't merge travel moves.
        {
            return false;
        }
        if (first_path.config != second_path.config) //Only merge lines that have the same type.
        {
            return false;
        }
        if (first_path.config->type != PrintFeatureType::Infill && first_path.config->type != PrintFeatureType::Skin) //Only merge skin and infill lines.
        {
            return false;
        }
        if ((!first_is_already_merged && first_path.points.size() > 1) || second_path.points.size() > 1)
        {
            // For now we only merge simple lines, not polylines, to keep it simple.
            // If the first line is already a merged line, then allow it.
            return false;
        }

        const Point first_path_end = first_path.points.back();
        const Point second_path_end = second_path.points.back();
        const Point first_direction = first_path_end - first_path_start;
        const Point second_direction = second_path_end - second_path_start;
        const coord_t dot_product = dot(first_direction, second_direction);
        const coord_t first_size = vSize(first_direction);  // it's an estimate if first_is_already_merged as it may contain more points, but we're mostly going one direction
        const coord_t second_size = vSize(second_direction);
        const coord_t line_width = first_path.config->getLineWidth();
        // restrict length
        if (!first_is_already_merged && first_size > 3 * line_width)
        {
            return false;
        }
        if (second_size > 3 * line_width)
        {
            return false;
        }

        //Check if lines are connected end-to-end and can be merged that way.
        if (vSize2(first_path_end - second_path_start) < line_width * line_width || vSize2(first_path_start - second_path_end) < line_width * line_width) //Paths are already (practically) connected, end-to-end.
        {
            //Only merge if lines are more or less in the same direction.
            const bool is_straight = dot_product + 400 > first_size * second_size; //400 = 20*20, where 20 micron is the allowed inaccuracy in the dot product, allowing a slight curve.
            if (is_straight) {
                mergeLinesSharedEndStartPoint(first_path, first_path_start, second_path, second_path_start);
                return true;
            }
        }

        //Lines may be adjacent side-by-side then.
        Point first_path_leave_point;
        coord_t merged_size2;
        if (first_is_already_merged) {
            first_path_leave_point = first_path.points.back();  // this is the point that's going to merge
        } else {
            first_path_leave_point = (first_path_start + first_path_end) / 2;
        }
        const Point second_path_destination_point = (second_path_start + second_path_end) / 2;
        const Point merged_direction = second_path_destination_point - first_path_leave_point;
        if (first_is_already_merged)
        {
            merged_size2 = vSize2(second_path_destination_point - first_path.points.back());  // check distance with last point in merged line that is to be replaced
        }
        else
        {
            merged_size2 = vSize2(merged_direction);
        }
        if (merged_size2 > 25 * line_width * line_width)
        {
            return false; //Lines are too far away from each other.
        }
        if (LinearAlg2D::getDist2FromLine(first_path_start,  second_path_destination_point, second_path_destination_point + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(first_path_end, second_path_destination_point, second_path_destination_point + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_start, first_path_leave_point, first_path_leave_point + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_end,   first_path_leave_point, first_path_leave_point + merged_direction) > 4 * line_width * line_width)
        {
            return false; //One of the lines is too far from the merged line. Lines would be too wide or too far off.
        }
        if (first_is_already_merged && first_path.points.size() > 1 && first_path.points[first_path.points.size() - 2] == second_path_destination_point)  // yes this can actually happen
        {
            return false;
        }

        mergeLinesSideBySide(first_is_already_merged, first_path, first_path_start, second_path, second_path_start);
        return true;
    }

    bool MergeInfillLines::mergeInfillLines(std::vector<GCodePath>& paths, const Point starting_position) const
    {
        /* Algorithm overview:
            1. Loop over all lines to see if they can be merged.
            1a. Check if two adjacent lines can be merged (skipping travel moves in
                between).
            1b. If they can, merge both lines into the first line.
            1c. If they are merged, check next that the first line can be merged
                with the line after the second line.
            2. Do a second iteration over all paths to remove the tombstones. */
        std::vector<size_t> remove_path_indices;
        std::set<size_t> is_merged;
        std::set<size_t> removed;  // keep track of what we already removed, so don't remove it again

        //For each two adjacent lines, see if they can be merged.
        size_t first_path_index = 0;
        Point first_path_start = starting_position;
        size_t second_path_index = 1;

        for (; second_path_index < paths.size(); second_path_index++)
        {
            GCodePath& first_path = paths[first_path_index];
            GCodePath& second_path = paths[second_path_index];
            Point second_path_start = paths[second_path_index - 1].points.back();
            if (second_path.config->isTravelPath())
            {
                continue; //Skip travel paths.
            }

            if (tryMerge(is_merged.find(first_path_index) != is_merged.end(), first_path, first_path_start, second_path, second_path_start))
            {
                /* If we combine two lines, the next path may also be merged into the fist line, so we do NOT update
                first_path_index. */
                for (size_t to_delete_index = first_path_index + 1; to_delete_index <= second_path_index; to_delete_index++)
                {
                    if (removed.find(to_delete_index) == removed.end())  // if there are line(s) between first and second, then those lines are already marked as to be deleted, only add the new line(s)
                    {
                        remove_path_indices.push_back(to_delete_index);
                        removed.insert(to_delete_index);
                    }
                }
                is_merged.insert(first_path_index);
            }
            else
            {
                /* If we do not combine, the next iteration we must simply merge the
                second path with the line after it. */
                first_path_index = second_path_index;
                first_path_start = second_path_start;
            }
        }

        //Delete all removed lines in one pass so that we need to move lines less often.
        if (!remove_path_indices.empty())
        {
            size_t path_index = remove_path_indices[0];
            for (size_t removed_position = 1; removed_position < remove_path_indices.size(); removed_position++)
            {
                for (; path_index < remove_path_indices[removed_position] - removed_position; path_index++)
                {
                    paths[path_index] = paths[path_index + removed_position]; //Shift all paths.
                }
            }
            for (; path_index < paths.size() - remove_path_indices.size(); path_index++) //Remaining shifts at the end.
            {
                paths[path_index] = paths[path_index + remove_path_indices.size()];
            }
            paths.erase(paths.begin() + path_index, paths.end());
            return true;
        }
        else
        {
            return false;
        }
    }
}//namespace cura
<commit_msg>Comment. CURA_5535<commit_after>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "utils/linearAlg2D.h" //Distance from point to line.
#include "MergeInfillLines.h"

namespace cura
{

    MergeInfillLines::MergeInfillLines(ExtruderPlan& plan) : extruder_plan(plan)
    {
        //Just copy the parameters to their fields.
    }

    void MergeInfillLines::mergeLinesSharedEndStartPoint(GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start) const
    {
        for (const Point second_path_point : second_path.points)
        {
            first_path.points.push_back(second_path_point); //Move the coordinates over to the first path.
        }
    }

    void MergeInfillLines::mergeLinesSideBySide(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start) const
    {
        coord_t first_path_length_flow = 0;
        Point average_first_path;

        Point previous_point = first_path_start;
        for (const Point point : first_path.points)
        {
            first_path_length_flow += vSize(point - previous_point);
            previous_point = point;
        }
        first_path_length_flow *= first_path.flow; //To get the volume we don't need to include the line width since it's the same for both lines.

        if (first_is_already_merged)
        {
            // take second point of path, first_path.points[0]
            average_first_path = first_path.points[0];
        }
        else
        {
            average_first_path += first_path_start;
            for (const Point point : first_path.points)
            {
                average_first_path += point;
            }
            average_first_path /= (first_path.points.size() + 1);
        }

        coord_t second_path_length_flow = 0;
        Point previous_point_second = second_path_start;
        Point average_second_path = second_path_start;
        for (const Point point : second_path.points)
        {
            second_path_length_flow += vSize(point - previous_point_second);
            average_second_path += point;
            previous_point_second = point;
        }
        second_path_length_flow *= second_path.flow;
        average_second_path /= (second_path.points.size() + 1);

        coord_t new_path_length = 0;

        if (first_is_already_merged)
        {
            // check if the new point is a good extension of last part of existing polyline
            // because of potential accumulation of errors introduced each time a line is merged, we do not allow any error.
            if (first_path.points.size() > 1 && LinearAlg2D::getDist2FromLine(average_second_path, first_path.points[first_path.points.size()-2], first_path.points[first_path.points.size()-1]) == 0) {
                first_path.points[first_path.points.size()-1] = average_second_path;
            } else {
                first_path.points.push_back(average_second_path);
            }
        }
        else
        {
            first_path.points.clear();
            first_path.points.push_back(average_first_path);
            first_path.points.push_back(average_second_path);
        }
        previous_point = first_path_start;
        for (const Point point : first_path.points)
        {
            new_path_length += vSize(point - previous_point);
            previous_point = point;
        }

        first_path.flow = static_cast<double>(first_path_length_flow + second_path_length_flow) / new_path_length;
    }

    bool MergeInfillLines::tryMerge(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, Point second_path_start) const
    {
        if (first_path.config->isTravelPath()) //Don't merge travel moves.
        {
            return false;
        }
        if (first_path.config != second_path.config) //Only merge lines that have the same type.
        {
            return false;
        }
        if (first_path.config->type != PrintFeatureType::Infill && first_path.config->type != PrintFeatureType::Skin) //Only merge skin and infill lines.
        {
            return false;
        }
        if ((!first_is_already_merged && first_path.points.size() > 1) || second_path.points.size() > 1)
        {
            // For now we only merge simple lines, not polylines, to keep it simple.
            // If the first line is already a merged line, then allow it.
            return false;
        }

        const Point first_path_end = first_path.points.back();
        const Point second_path_end = second_path.points.back();
        const Point first_direction = first_path_end - first_path_start;
        const Point second_direction = second_path_end - second_path_start;
        const coord_t dot_product = dot(first_direction, second_direction);
        const coord_t first_size = vSize(first_direction);  // it's an estimate if first_is_already_merged as it may contain more points, but we're mostly going one direction
        const coord_t second_size = vSize(second_direction);
        const coord_t line_width = first_path.config->getLineWidth();
        //Restrict length, this prevents wide gaps to be filled with a very wide line.
        if (!first_is_already_merged && first_size > 3 * line_width)
        {
            return false;
        }
        if (second_size > 3 * line_width)
        {
            return false;
        }

        //Check if lines are connected end-to-end and can be merged that way.
        if (vSize2(first_path_end - second_path_start) < line_width * line_width || vSize2(first_path_start - second_path_end) < line_width * line_width) //Paths are already (practically) connected, end-to-end.
        {
            //Only merge if lines are more or less in the same direction.
            const bool is_straight = dot_product + 400 > first_size * second_size; //400 = 20*20, where 20 micron is the allowed inaccuracy in the dot product, allowing a slight curve.
            if (is_straight) {
                mergeLinesSharedEndStartPoint(first_path, first_path_start, second_path, second_path_start);
                return true;
            }
        }

        //Lines may be adjacent side-by-side then.
        Point first_path_leave_point;
        coord_t merged_size2;
        if (first_is_already_merged) {
            first_path_leave_point = first_path.points.back();  // this is the point that's going to merge
        } else {
            first_path_leave_point = (first_path_start + first_path_end) / 2;
        }
        const Point second_path_destination_point = (second_path_start + second_path_end) / 2;
        const Point merged_direction = second_path_destination_point - first_path_leave_point;
        if (first_is_already_merged)
        {
            merged_size2 = vSize2(second_path_destination_point - first_path.points.back());  // check distance with last point in merged line that is to be replaced
        }
        else
        {
            merged_size2 = vSize2(merged_direction);
        }
        if (merged_size2 > 25 * line_width * line_width)
        {
            return false; //Lines are too far away from each other.
        }
        if (LinearAlg2D::getDist2FromLine(first_path_start,  second_path_destination_point, second_path_destination_point + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(first_path_end, second_path_destination_point, second_path_destination_point + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_start, first_path_leave_point, first_path_leave_point + merged_direction) > 4 * line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_end,   first_path_leave_point, first_path_leave_point + merged_direction) > 4 * line_width * line_width)
        {
            return false; //One of the lines is too far from the merged line. Lines would be too wide or too far off.
        }
        if (first_is_already_merged && first_path.points.size() > 1 && first_path.points[first_path.points.size() - 2] == second_path_destination_point)  // yes this can actually happen
        {
            return false;
        }

        mergeLinesSideBySide(first_is_already_merged, first_path, first_path_start, second_path, second_path_start);
        return true;
    }

    bool MergeInfillLines::mergeInfillLines(std::vector<GCodePath>& paths, const Point starting_position) const
    {
        /* Algorithm overview:
            1. Loop over all lines to see if they can be merged.
            1a. Check if two adjacent lines can be merged (skipping travel moves in
                between).
            1b. If they can, merge both lines into the first line.
            1c. If they are merged, check next that the first line can be merged
                with the line after the second line.
            2. Do a second iteration over all paths to remove the tombstones. */
        std::vector<size_t> remove_path_indices;
        std::set<size_t> is_merged;
        std::set<size_t> removed;  // keep track of what we already removed, so don't remove it again

        //For each two adjacent lines, see if they can be merged.
        size_t first_path_index = 0;
        Point first_path_start = starting_position;
        size_t second_path_index = 1;

        for (; second_path_index < paths.size(); second_path_index++)
        {
            GCodePath& first_path = paths[first_path_index];
            GCodePath& second_path = paths[second_path_index];
            Point second_path_start = paths[second_path_index - 1].points.back();
            if (second_path.config->isTravelPath())
            {
                continue; //Skip travel paths.
            }

            if (tryMerge(is_merged.find(first_path_index) != is_merged.end(), first_path, first_path_start, second_path, second_path_start))
            {
                /* If we combine two lines, the next path may also be merged into the fist line, so we do NOT update
                first_path_index. */
                for (size_t to_delete_index = first_path_index + 1; to_delete_index <= second_path_index; to_delete_index++)
                {
                    if (removed.find(to_delete_index) == removed.end())  // if there are line(s) between first and second, then those lines are already marked as to be deleted, only add the new line(s)
                    {
                        remove_path_indices.push_back(to_delete_index);
                        removed.insert(to_delete_index);
                    }
                }
                is_merged.insert(first_path_index);
            }
            else
            {
                /* If we do not combine, the next iteration we must simply merge the
                second path with the line after it. */
                first_path_index = second_path_index;
                first_path_start = second_path_start;
            }
        }

        //Delete all removed lines in one pass so that we need to move lines less often.
        if (!remove_path_indices.empty())
        {
            size_t path_index = remove_path_indices[0];
            for (size_t removed_position = 1; removed_position < remove_path_indices.size(); removed_position++)
            {
                for (; path_index < remove_path_indices[removed_position] - removed_position; path_index++)
                {
                    paths[path_index] = paths[path_index + removed_position]; //Shift all paths.
                }
            }
            for (; path_index < paths.size() - remove_path_indices.size(); path_index++) //Remaining shifts at the end.
            {
                paths[path_index] = paths[path_index + remove_path_indices.size()];
            }
            paths.erase(paths.begin() + path_index, paths.end());
            return true;
        }
        else
        {
            return false;
        }
    }
}//namespace cura
<|endoftext|>


<commit_before>/*
	how to use
*/
#include <stdio.h>
#include <cybozu/option.hpp>
#include <vector>

struct A : public cybozu::Option {
	int x;
	bool b;
	double d;
	std::string y;
	std::vector<int> z;
	std::vector<std::string> w;
	std::string inName;
	std::vector<std::string> r;
	std::vector<std::string> vi;
	uint64_t u;
	A()
	{
		appendOpt(&x, 5, "x", "int");
		appendOpt(&b, false, "b", "bool");
		appendMust(&d, "d", "double");
		appendMust(&y, "y", "string");
		appendVec(&z, "z", "int int int ...");
		appendVec(&w, "w", "str str str ...");
		appendOpt(&u, 0, "u", "uint64 val");
		appendParam(&inName, "input-file", "text file");
		appendParamVec(&vi, "remains", "sss");
		appendHelp("h");
	}
};

int main(int argc, char *argv[])
	try
{
	A a;
	if (a.parse(argc, argv)) {
		a.put();
	} else {
		a.usage();
	}
} catch (std::exception& e) {
	printf("ERR %s\n", e.what());
}
<commit_msg>avoid drived class<commit_after>/*
	how to use
*/
#include <stdio.h>
#include <cybozu/option.hpp>
#include <vector>

int main(int argc, char *argv[])
	try
{
	int x;
	bool b;
	double d;
	std::string y;
	std::vector<int> z;
	std::vector<std::string> w;
	std::string inName;
	std::vector<std::string> r;
	std::vector<std::string> vi;
	uint64_t u;

	cybozu::Option opt;

	opt.appendOpt(&x, 5, "x", "int");
	opt.appendOpt(&b, false, "b", "bool");
	opt.appendMust(&d, "d", "double");
	opt.appendMust(&y, "y", "string");
	opt.appendVec(&z, "z", "int int int ...");
	opt.appendVec(&w, "w", "str str str ...");
	opt.appendOpt(&u, 0, "u", "uint64 val");
	opt.appendParam(&inName, "input-file", "text file");
	opt.appendParamVec(&vi, "remains", "sss");
	opt.appendHelp("h");

	if (opt.parse(argc, argv)) {
		opt.put();
	} else {
		opt.usage();
	}
} catch (std::exception& e) {
	printf("ERR %s\n", e.what());
}
<|endoftext|>


<commit_before>#include "CameraForm.h"
#include "Object.h"
#include "Director.h"
#include "TransformPipelineParam.h"

using namespace Math;
using namespace std;
using namespace Rendering::Light;
using namespace Device;
using namespace Core;
using namespace Rendering::Camera;
using namespace Rendering::Manager;

CameraForm::CameraForm()
	: Component(), _frustum(nullptr), _renderTarget(nullptr)
{
}

CameraForm::~CameraForm(void)
{

}

void CameraForm::OnInitialize()
{
	_fieldOfViewDegree	= 60.0f;
	_clippingNear		= 0.1f;
	_clippingFar		= 1000.0f;

	const Size<unsigned int>& backBufferSize = Director::GetInstance()->GetBackBufferSize();
	_aspect = (float)backBufferSize.w / (float)backBufferSize.h;

	_projectionType    = ProjectionType::Perspective;
	_clearColor = Color(0.5f, 0.5f, 1.0f, 1.0f);

	_frustum = new Frustum(0.0f);

	_renderTarget = new Texture::RenderTexture;
	_renderTarget->Initialize(backBufferSize, DXGI_FORMAT_R8G8B8A8_UNORM);

	_camConstBuffer = new Buffer::ConstBuffer;
	if(_camConstBuffer->Initialize(sizeof(ConstBufferParam)) == false)
		ASSERT_MSG("Error, cam->constbuffer->Initialize");

	//_clearFlag = ClearFlag::FlagSolidColor;
}

void CameraForm::OnDestroy()
{
	SAFE_DELETE(_frustum);
	SAFE_DELETE(_renderTarget);
}

void CameraForm::CalcAspect()
{
	const Size<unsigned int>& backBufferSize =  Device::Director::GetInstance()->GetBackBufferSize();
	_aspect = (float)backBufferSize.w / (float)backBufferSize.h;
}

void CameraForm::GetProjectionMatrix(Math::Matrix& outMatrix) const
{
	if(_projectionType == ProjectionType::Perspective)
	{
		float fovRadian = Math::Common::Deg2Rad(_fieldOfViewDegree);
		Matrix::PerspectiveFovLH(outMatrix, _aspect, fovRadian, _clippingFar, _clippingNear);
	}
	else if(_projectionType == ProjectionType::Orthographic)
	{
		const Size<unsigned int>& backBufferSize = Device::Director::GetInstance()->GetBackBufferSize();
		Matrix::OrthoLH(outMatrix, (float)(backBufferSize.w), (float)(backBufferSize.h), _clippingNear, _clippingFar);
	}
}

void CameraForm::GetViewMatrix(Math::Matrix &outMatrix, const Math::Matrix &worldMatrix)
{
	outMatrix = worldMatrix;

	Vector3 worldPos;
	worldPos.x = worldMatrix._41;
	worldPos.y = worldMatrix._42;
	worldPos.z = worldMatrix._43;

	Math::Vector3 right		= Math::Vector3(worldMatrix._11, worldMatrix._21, worldMatrix._31);
	Math::Vector3 up		= Math::Vector3(worldMatrix._12, worldMatrix._22, worldMatrix._32);
	Math::Vector3 forward	= Math::Vector3(worldMatrix._13, worldMatrix._23, worldMatrix._33);

	Vector3 p;
	p.x = -Vector3::Dot(right,		worldPos);
	p.y = -Vector3::Dot(up,			worldPos);
	p.z = -Vector3::Dot(forward,	worldPos);

	outMatrix._41 = p.x;
	outMatrix._42 = p.y;
	outMatrix._43 = p.z;
	outMatrix._44 = 1.0f;
}

void CameraForm::GetViewMatrix(Math::Matrix& outMatrix) const
{
	Matrix worldMat;
	_owner->GetTransform()->FetchWorldMatrix(worldMat);

	GetViewMatrix(outMatrix, worldMat);
}

void CameraForm::RenderPreviewWithUpdateTransformCB(const std::vector<Core::Object*>& objects)
{
	TransformPipelineParam tfParam;
	GetProjectionMatrix(tfParam.projMat);
	GetViewMatrix(tfParam.viewMat);

	_viewProjMatrixInPrevRenderState = tfParam.viewMat * tfParam.projMat;
	_frustum->Make(_viewProjMatrixInPrevRenderState);

	ConstBufferParam camCB;
	{
		Matrix worldMat;
		_owner->GetTransform()->FetchWorldMatrix(worldMat);

		camCB.worldPos		= Vector4(worldMat._41, worldMat._42, worldMat._43, 1.0f);
		camCB.clippingNear	= _clippingNear;
		camCB.clippingFar	= _clippingFar;
		camCB.screenSize	= Device::Director::GetInstance()->GetBackBufferSize().Cast<float>();
	}

	if( memcmp(&_prevConstBufferData, &camCB, sizeof(ConstBufferParam)) != 0 )
	{
		ID3D11DeviceContext* context = Device::Director::GetInstance()->GetDirectX()->GetContext();
		_camConstBuffer->UpdateSubResource(context, &camCB);

		_prevConstBufferData = camCB;
	}

	for(auto iter = objects.begin(); iter != objects.end(); ++iter)
	{
		(*iter)->Culling(_frustum);
		(*iter)->RenderPreviewWithUpdateTransformCB(tfParam);
	}
}

void CameraForm::SortTransparentMeshRenderQueue(const RenderManager* renderMgr)
{
	const RenderManager::MeshList transparentList = renderMgr->GetTransparentMeshes();
	if( transparentList.updateCounter > _transparentMeshQueue.updateCounter )
	{
		const auto& meshes = transparentList.meshes.GetVector();

		_transparentMeshQueue.meshes.clear();
		for(auto iter = meshes.begin(); iter != meshes.end(); ++iter)
			_transparentMeshQueue.meshes.push_back((*iter));

		_transparentMeshQueue.updateCounter = transparentList.updateCounter;
	}

	const Transform* transform = _owner->GetTransform();

	Math::Vector3 camPos;
	transform->FetchWorldPosition(camPos);

	auto SortingByDistance = [&](const Mesh::Mesh*& left, const Mesh::Mesh*& right) -> bool
	{
		float leftDistance = D3D11_FLOAT32_MAX;
		{
			Math::Vector3 leftPos;
			left->GetOwner()->GetTransform()->FetchWorldPosition(leftPos);
			leftDistance = Math::Vector3::Distance(leftPos, camPos);
		}

		float rightDistance = D3D11_FLOAT32_MAX;
		{
			Math::Vector3 rightPos;
			right->GetOwner()->GetTransform()->FetchWorldPosition(rightPos);
			rightDistance = Math::Vector3::Distance(rightPos, camPos);
		}

		return leftDistance < rightDistance;
	};

	std::sort(_transparentMeshQueue.meshes.begin(), _transparentMeshQueue.meshes.end(), SortingByDistance);
}

void CameraForm::_Clone(CameraForm* newCam) const
{
	(*newCam) = (*this);
	newCam->_frustum		= new Frustum(0.0f);
	newCam->_renderTarget	= new Texture::RenderTexture;
	{
		const Size<unsigned int>& size = Director::GetInstance()->GetBackBufferSize();
		newCam->_renderTarget->Initialize(size, DXGI_FORMAT_R8G8B8A8_UNORM);
	}

	newCam->_camConstBuffer	= new Buffer::ConstBuffer;
	if(_camConstBuffer->Initialize(sizeof(ConstBufferParam)) == false)
		ASSERT_MSG("Error, cant create const buffer in _Clone");
}<commit_msg>CameraForm - 코드 정리 #64<commit_after>#include "CameraForm.h"
#include "Object.h"
#include "Director.h"
#include "TransformPipelineParam.h"

using namespace Math;
using namespace std;
using namespace Rendering::Light;
using namespace Device;
using namespace Core;
using namespace Rendering::Camera;
using namespace Rendering::Manager;

CameraForm::CameraForm()
	: Component(), _frustum(nullptr), _renderTarget(nullptr)
{
}

CameraForm::~CameraForm(void)
{

}

void CameraForm::OnInitialize()
{
	_fieldOfViewDegree	= 60.0f;
	_clippingNear		= 0.1f;
	_clippingFar		= 1000.0f;

	const Size<unsigned int>& backBufferSize = Director::GetInstance()->GetBackBufferSize();
	_aspect = (float)backBufferSize.w / (float)backBufferSize.h;

	_projectionType    = ProjectionType::Perspective;
	_clearColor = Color(0.5f, 0.5f, 1.0f, 1.0f);

	_frustum = new Frustum(0.0f);

	_renderTarget = new Texture::RenderTexture;
	_renderTarget->Initialize(backBufferSize, DXGI_FORMAT_R8G8B8A8_UNORM);

	_camConstBuffer = new Buffer::ConstBuffer;
	if(_camConstBuffer->Initialize(sizeof(ConstBufferParam)) == false)
		ASSERT_MSG("Error, cam->constbuffer->Initialize");

	//_clearFlag = ClearFlag::FlagSolidColor;
}

void CameraForm::OnDestroy()
{
	SAFE_DELETE(_frustum);
	SAFE_DELETE(_renderTarget);
}

void CameraForm::CalcAspect()
{
	const Size<unsigned int>& backBufferSize =  Device::Director::GetInstance()->GetBackBufferSize();
	_aspect = (float)backBufferSize.w / (float)backBufferSize.h;
}

void CameraForm::GetProjectionMatrix(Math::Matrix& outMatrix) const
{
	if(_projectionType == ProjectionType::Perspective)
	{
		float fovRadian = Math::Common::Deg2Rad(_fieldOfViewDegree);
		Matrix::PerspectiveFovLH(outMatrix, _aspect, fovRadian, _clippingFar, _clippingNear);
	}
	else if(_projectionType == ProjectionType::Orthographic)
	{
		const Size<unsigned int>& backBufferSize = Device::Director::GetInstance()->GetBackBufferSize();
		Matrix::OrthoLH(outMatrix, (float)(backBufferSize.w), (float)(backBufferSize.h), _clippingNear, _clippingFar);
	}
}

void CameraForm::GetViewMatrix(Math::Matrix &outMatrix, const Math::Matrix &worldMatrix)
{
	outMatrix = worldMatrix;

	Vector3 worldPos;
	worldPos.x = worldMatrix._41;
	worldPos.y = worldMatrix._42;
	worldPos.z = worldMatrix._43;

	Math::Vector3 right		= Math::Vector3(worldMatrix._11, worldMatrix._21, worldMatrix._31);
	Math::Vector3 up		= Math::Vector3(worldMatrix._12, worldMatrix._22, worldMatrix._32);
	Math::Vector3 forward	= Math::Vector3(worldMatrix._13, worldMatrix._23, worldMatrix._33);

	Vector3 p;
	p.x = -Vector3::Dot(right,		worldPos);
	p.y = -Vector3::Dot(up,			worldPos);
	p.z = -Vector3::Dot(forward,	worldPos);

	outMatrix._41 = p.x;
	outMatrix._42 = p.y;
	outMatrix._43 = p.z;
	outMatrix._44 = 1.0f;
}

void CameraForm::GetViewMatrix(Math::Matrix& outMatrix) const
{
	Matrix worldMat;
	_owner->GetTransform()->FetchWorldMatrix(worldMat);

	GetViewMatrix(outMatrix, worldMat);
}

void CameraForm::RenderPreviewWithUpdateTransformCB(const std::vector<Core::Object*>& objects)
{
	TransformPipelineParam tfParam;
	GetProjectionMatrix(tfParam.projMat);
	GetViewMatrix(tfParam.viewMat);

	_viewProjMatrixInPrevRenderState = tfParam.viewMat * tfParam.projMat;
	_frustum->Make(_viewProjMatrixInPrevRenderState);

	ConstBufferParam camCB;
	{
		Matrix worldMat;
		_owner->GetTransform()->FetchWorldMatrix(worldMat);

		camCB.worldPos		= Vector4(worldMat._41, worldMat._42, worldMat._43, 1.0f);
		camCB.clippingNear	= _clippingNear;
		camCB.clippingFar	= _clippingFar;
		camCB.screenSize	= Device::Director::GetInstance()->GetBackBufferSize().Cast<float>();
	}

	if( memcmp(&_prevConstBufferData, &camCB, sizeof(ConstBufferParam)) != 0 )
	{
		ID3D11DeviceContext* context = Device::Director::GetInstance()->GetDirectX()->GetContext();
		_camConstBuffer->UpdateSubResource(context, &camCB);

		_prevConstBufferData = camCB;
	}

	for(auto iter = objects.begin(); iter != objects.end(); ++iter)
	{
		(*iter)->Culling(_frustum);
		(*iter)->RenderPreviewWithUpdateTransformCB(tfParam);
	}
}

void CameraForm::SortTransparentMeshRenderQueue(const RenderManager* renderMgr)
{
	const RenderManager::MeshList transparentList = renderMgr->GetTransparentMeshes();
	if( transparentList.updateCounter > _transparentMeshQueue.updateCounter )
	{
		const auto& renderMgrMeshes = transparentList.meshes.GetVector();
		auto& thisCamMeshes = _transparentMeshQueue.meshes;

		thisCamMeshes.clear();
		thisCamMeshes.insert( thisCamMeshes.end(), renderMgrMeshes.begin(), renderMgrMeshes.end());

		_transparentMeshQueue.updateCounter = transparentList.updateCounter;
	}

	const Transform* transform = _owner->GetTransform();

	Math::Vector3 camPos;
	transform->FetchWorldPosition(camPos);

	auto SortingByDistance = [&](const Mesh::Mesh*& left, const Mesh::Mesh*& right) -> bool
	{
		float leftDistance = D3D11_FLOAT32_MAX;
		{
			Math::Vector3 leftPos;
			left->GetOwner()->GetTransform()->FetchWorldPosition(leftPos);
			leftDistance = Math::Vector3::Distance(leftPos, camPos);
		}

		float rightDistance = D3D11_FLOAT32_MAX;
		{
			Math::Vector3 rightPos;
			right->GetOwner()->GetTransform()->FetchWorldPosition(rightPos);
			rightDistance = Math::Vector3::Distance(rightPos, camPos);
		}

		return leftDistance < rightDistance;
	};

	std::sort(_transparentMeshQueue.meshes.begin(), _transparentMeshQueue.meshes.end(), SortingByDistance);
}

void CameraForm::_Clone(CameraForm* newCam) const
{
	(*newCam) = (*this);
	newCam->_frustum		= new Frustum(0.0f);
	newCam->_renderTarget	= new Texture::RenderTexture;
	{
		const Size<unsigned int>& size = Director::GetInstance()->GetBackBufferSize();
		newCam->_renderTarget->Initialize(size, DXGI_FORMAT_R8G8B8A8_UNORM);
	}

	newCam->_camConstBuffer	= new Buffer::ConstBuffer;
	if(_camConstBuffer->Initialize(sizeof(ConstBufferParam)) == false)
		ASSERT_MSG("Error, cant create const buffer in _Clone");
}<|endoftext|>