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" ...
随机推荐
- 基本类型和引用类型的值 [重温JavaScript基础(一)]
前言: JavaScript 的变量与其他语言的变量有很大区别.JavaScript 变量松散类型的本质,决定了它只是在特定时间用于保存特定值的一个名字而已.由于不存在定义某个变量必须要保存何种数据类 ...
- Maven使用和配置
Maven使用和配置 一.maven安装和概念 maven安装 maven编译(compile) 执行测试用例(test) maven打包(package) maven依赖管理 1.maven安装 官 ...
- 黑客必学之“网页木马webshell”
摘要: 这节课,我们来了解一下网页的木马,首先我们了解网页木马之前,先来了解一下什么是一句话木马.小马和大马.什么是webshell首先简单说一下webshell,webshell简单来说就是黑客植入 ...
- 使用QT绘制一个多边形
目录 1. 概述 2. 实现 2.1. 代码 2.2. 解析 3. 结果 1. 概述 可以通过QT的重绘事件和鼠标事件来绘制多边形,最简单的办法就是在继承QWidget的窗体中重写paintEvent ...
- XCTF---easyjava的WriteUp
一.题目来源 题目来源:XCTF题库安卓区easyjava 题目下载链接:下载地址 二.解题过程 1.将该apk安装进夜神模拟器中,发现有一个输入框和一个按钮,随便输入信息,点 ...
- 使用java短信验证
package cn.geekss.util; import java.io.BufferedReader;import java.io.InputStreamReader;import java.i ...
- 误删除所有redo日志的一组成员的处理过程
系统中共有3个日志文件组,每个组中各有一个日志文件成员.往系统中添加一个日志文件组,组中日志文件成员数量是2.SQL> alter database add logfile group 4 (' ...
- 简单配置Vue路由
简单配置Vue路由 1. 创建一个单文件组件Test.vue <template> <div>Test</div> </template> <s ...
- C语言程序设计(三) 简单的算术运算和表达式
第三章 简单的算术运算和表达式 算数运算符:一元.二元.三元(条件运算符) 1/2是整型除法,1.0/2是浮点数除法 求余运算(%)限定参与运算的两个操作数必须为整数,不能对两个实型数据进行求余运算 ...
- C#如何实现大小写转换
2020-03-16 每日一例第8天 1.新建窗体应用程序,拖入label/textbox/radiobutton控件,并改text值: 2.button控件输入代码: if (radioButt ...