Post date: Mar 23, 2016 11:19:07 AM
やりたいのはこういうふうに,赤い多角形を渡したら,一回り大きい(小さい)多角形(青)を出力する,というもの.
普通何も考えずに伸縮すると幅の厚いところと薄いところができてしまう.凸じゃないとめり込んでしまったりする.
緑の多角形は,もともとの多角形のすべての頂点の平均を中心に1.2倍に拡大したもの.
ということで,ストローク(多角形)の角度を考慮して拡大をしてみる.
ストロークのうち連続した3点を取り出す.それらを順に,A,O,Bとする.
上図のようにベクトルをとって正規化をする.それらを足してやると,ちょうど角の外側へのベクトル(適当に膨張ベクトルとか呼んどく)が取れる.
さて,右隣の頂点を見ていただければわかるが,この方法だと,凹のぶぶんでは内側に凹んでしまう.そこで,できた膨張ベクトルと壁の向きを揃えていく.
Processingのソースコード.
import java.util.*;
ArrayList<PVector> line=null;
PVector frame[], frame2[];
void setup() {
size(800, 600, P3D);
frame=new PVector[4];
frame[0]=new PVector(100, 100);
frame[1]=new PVector(100, 500);
frame[2]=new PVector(700, 500);
frame[3]=new PVector(700, 100);
createOutFrame();
}
void draw() {
background(255);
if (line!=null) {
stroke(0);
line.add(new PVector(mouseX, mouseY));
beginShape();
for (PVector pv : line) {
vertex(pv.x, pv.y);
}
endShape();
}
if (frame!=null) {
stroke(255, 0, 0);
beginShape();
for (PVector pv : frame) {
vertex(pv.x, pv.y);
}
endShape(CLOSE);
}
if (frame2!=null) {
stroke(0, 0, 255);
beginShape();
for (PVector pv : frame2) {
vertex(pv.x, pv.y);
}
endShape(CLOSE);
}
}
void mousePressed() {
if (mouseButton==LEFT) {
line=new ArrayList<PVector>();
}
}
void mouseReleased() {
if (line!=null) {
ArrayList<PVector> aaa=new ArrayList<PVector>();
PVector old=null;
for (PVector p : line) {
if (old==null) {
aaa.add(p);
old=p;
continue;
}
if (PVector.dist(p, old)<1) {
continue;
}
aaa.add(p);
old=p;
}
frame=aaa.toArray(new PVector[0]);
line=null;
createOutFrame();
}
}
void createOutFrame() {
float time=10;
frame2=new PVector[frame.length];
float ang=0;
for (int i=0; i<frame.length; i++) {
PVector A=frame[(frame.length+i-1)%frame.length];
PVector O=frame[i];
PVector B=frame[(i+1)%frame.length];
PVector AO=PVector.sub(O, A);
PVector OB=PVector.sub(B, O);
AO.normalize();
OB.normalize();
ang+=AO.x*OB.y-AO.y*OB.x;
}
for (int i=0; i<frame.length; i++) {
PVector A=frame[(frame.length+i-1)%frame.length];
PVector O=frame[i];
PVector B=frame[(i+1)%frame.length];
PVector AO=PVector.sub(O, A);
PVector BO=PVector.sub(O, B);
AO.normalize();
BO.normalize();
PVector dir=PVector.add(AO, BO);
dir.normalize();
if (dir.magSq()<0.1) {
BO.rotate(HALF_PI);
if (ang<0) {
BO.mult(-1);
}
BO.mult(time);
frame2[i]=new PVector(frame[i].x, frame[i].y);
frame2[i].add(BO);
continue;
}
if ((AO.x*dir.y-AO.y*dir.x)*ang>0) {
dir.mult(-1);
}
frame2[i]=new PVector(frame[i].x, frame[i].y);
dir.mult(time);
frame2[i].add(dir);
}
}