Drawing Simple Polygon(Create Simple Polygon from unordered points by angle sorting)
Keywords: 极角排序, Simple Polygon Generation
题意:
给了一组无序的平面点集,目标是构造出一个Simple Polygon, Simple Polygon相比Polygon的定义约束是要求Polygon无边自交(题目也有具体的描述)。
分析:
任意点序列看作一个Polygon。原始序列满足Simple Polygon的自交约束的对应序列可看作原始序列的特定Comparator下的排序结果。此处意味着可能存在一种Comparator, 通过其可套用通用的序列排序算法得到目标结果。
答案是对标Convex Hull问题的经典算法Graham Scan的presort子算法,也就是极角排序。极角排序是二维点集有序化的一个经典思路, 普通的axis-based sort可看作极点在无穷远处的一个特例, 同时Graham Scan后部分Scan可以直接处理任意的Simple Polygon或小修后处理axis-based sorted点序列。此时有某种直观指引: 通过Graham Scan的微修版presort可以解决Simple Polygon的构造问题。
多点共线(且其中一个点为极点)是极角排序需要补充定义进行处理的特殊情况, Graham Scan可将多点共线的处理延迟至Scan的实现上。补充多点共线点的偏序定义为极径增序,特例为入度方向相邻的共线区间为极径减序。
Why Impossible? All the Points are in a same line.
Code:
#include <iostream>
#include <array>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
namespace cglib {
template <class Type = int>
struct Vec2{
Type x, y;
Vec2(){}
Vec2(Type _x, Type _y): x(_x), y(_y){}
bool operator < (const Vec2& rhs) {
return y == rhs.y ? x < rhs.x : y < rhs.y;
}
Vec2 operator - (const Vec2& rhs) const {
return Vec2(rhs.x - x, rhs.y - y);
}
double length2() const {
return x * x + y * y;
}
};
using vec2i = Vec2<int>;
template <class Type>
int to_left_test(const Type p, const Type q, const Type s) {
int x = _Area(p, q, s);
return x == 0 ? -1: x > 0;
}
template <class Type>
int _Area(const Type& p, const Type& q, const Type& s) {
return p.x * q.y - p.y * q.x +
q.x * s.y - q.y * s.x +
s.x * p.y - s.y * p.x;
}
bool graham_presort(std::vector<vec2i>& P, std::vector<int>& idx) {
std::swap(idx[0], idx[std::min_element(P.begin(), P.end())-P.begin()]);
bool is_same_line = true;
std::sort(idx.begin()+1, idx.end(), [&](const int& lhs, const int& rhs)->bool{
switch (to_left_test(P[idx[0]], P[lhs], P[rhs])) {
case -1:
return (P[lhs]-P[idx[0]]).length2() < (P[rhs]-P[idx[0]]).length2();
case 0:
is_same_line = false;
return false;
case 1:
is_same_line = false;
return true;
}
});
if(!is_same_line) {
for(int i = idx.size()-2; i > 0; i--) {
if(to_left_test(P[idx[0]], P[*idx.rbegin()], P[idx[i]]) == -1) continue;
std::reverse(idx.begin()+i+1, idx.end());
break;
}
}
return !is_same_line;
}
}
int main() {
using namespace cglib;
int T, N;
std::cin >> T;
for(int t = 0; t < T; t++) {
std::cin >> N;
std::vector<vec2i> P;
vec2i p;
for(int i = 0; i < N; i++) {
std::cin >> p.x >> p.y;
P.emplace_back(p);
}
std::vector<int> idx(P.size());
for(int i = 0; i < idx.size(); i++) idx[i] = i;
std::cout << "Case " << t+1 << ":" << std::endl;
if( !graham_presort(P, idx) ) {
std::cout << "Impossible\n";
}
else {
for(int i = 0; i < idx.size()-1; i++)
std::cout << idx[i] << ' ';
std::cout << *idx.rbegin() << std::endl;
}
}
}
Drawing Simple Polygon(Create Simple Polygon from unordered points by angle sorting)的更多相关文章
- 46 Simple Python Exercises-Very simple exercises
46 Simple Python Exercises-Very simple exercises 4.Write a function that takes a character (i.e. a s ...
- how to change svg polygon size by update it's points in js
how to change svg polygon size by update it's points in js matrixTransform https://stackoverflow.com ...
- css create 多边形 polygon
案例: 代码: element.style { width: 0; height: 0; /* border-left: 50px solid transparent; */ border-rig ...
- libgdx 裁剪多边形(clip polygon、masking polygon)
直接放例子代码,代码中以任意四边形为例,如果需要做任意多边形,注意libgdx不能直接用ShapeRender填充多边形,需要先切割成三角形. public static void drawClip( ...
- Sass与Compress实战:第三章
概要:这一章将介绍Compass如何使Web设计中最基础的部分——布局变得简单. 本章内容: ● 网格布局的基本原理以及何时使用网格布局 ● 使用Compass时的CSS网格布局框架选项 ● 使用排版 ...
- Java JTS & 空间数据模型
空间数据模型 判断两个几何图形是否存在指定的空间关系.包括: 相等(equals).分离(disjoint).相交(intersect).相接(touches).交叉(crosses).包含于(wit ...
- (二)在实战中使用Sass和Compass
第三章 无需计算玩转CSS网格布局 3.1 网格布局介绍 3.2 使用网格布局 3.2.1 术语 术语名 定义 是否涉及HTML标签 列 内容度量的垂直单位 否 容器 构成一个网格布局的HTML元素 ...
- JTS基本概念和使用
简介 JTS是加拿大的 Vivid Solutions公司做的一套开放源码的 Java API.它提供了一套空间数据操作的核心算法.为在兼容OGC标准的空间对象模型中进行基础的几何操作提供2D空间谓词 ...
- D3、EChart、HighChart绘图demol
1.echarts: <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...
随机推荐
- 语言发展与python
编程语言的发展史(机械语言.汇编语言.高级语言) 机械语言:直接使用二进制与计算机沟通,直接操作硬件,执行效率高,开发效率低. 汇编语言:用简单的英文代替二进制,直接操作硬件,执行效率较机械语言低,开 ...
- 杂记:OSX 安装openssl
因为工作中要用到openssl中提供的MD5.SHA等摘要算法,通过brew install openssl安装的openssl在C文件中找不到相应的头文件.按照网上的教程各种修改之后还是找不到相应的 ...
- C++ Primer Plus 学习之 类继承
主要介绍了类的继承.虚函数.类继承的动态内存分配问题.继承与友元函数. 公有派生 基类的公有成员和私有成员都会成为派生类的一部分. 基类的私有成员只能通过基类的公有或者保护方法访问.但是,基类指针或引 ...
- android 中webview的屏幕适配问题
两行代码解决WebView的屏幕适配问题 一个简单的方法,让网页快速适应手机屏幕,代码如下 1 2 WebSettings webSettings= webView.getSettings(); we ...
- first-child和first-of-type
我想实现的效果:将第一个article字体颜色设置为红色 123456 <div? <h1>logo</h1> <article>article1</a ...
- Python爬虫-百度模拟登录(二)
上一篇-Python爬虫-百度模拟登录(一) 接上一篇的继续 参数 codestring codestring jxG9506c1811b44e2fd0220153643013f7e6b1898075 ...
- 【简单版】hexo博客搭建流程梳理
前言 本文章会为你梳理一个搭建hexo博客的流程 相关网址: Docs: https://hexo.io/docs/ Themes: https://hexo.io/themes/ 安装hexo 准备 ...
- Vue组件传递数据
组件命名 1.字母全小写且必须包含一个连字符 my-componnect 2.使用 kebab-case(短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例 ...
- python爬虫-scrapy日志
1.scrapy日志介绍 Scrapy的日志系统是实现了对python内置的日志的封装 scrapy也使用python日志级别分类 logging.CRITICAL logging.ERROE log ...
- 【视频+图文】带你快速掌握带continue语句的双重for循环
双重for循环掌握后,我们就一起来看看双重for循环的进阶内容一之带continue语句的双重for循环. 上期双重for循环[视频+图文]讲解传输门:点击这里可去小乔的哔哩哔哩观看for循环视频~ ...