多角形から曲線(円弧補間(4点))を生成するスクリプトです。

 閉じた多角形を選択すれば閉じた曲線になります。円弧補間(4点)の曲線がどのようなものかは、前の投稿をご覧下さい。


 注意:以下のスクリプトにはバグが多数あります。

procedure PolyToCurve;

{ 選択した多角形から曲線を作る(放物線補間(4点、2等分法)) }

{$ DEBUG}

label

999, 1000;

const

PolygonObj = 5;

nL = 5;

type

PointImfo = structure

dir :integer;

p, pc :vector;

rad, d :real;

hasArc, isArc :boolean;

end;

var

pt :dynArray[] of PointImfo;

i, iL, n :integer;

d :real;

p :vector;

hp, h, tmp :handle;

closed :boolean;

{$INCLUDE :vs_subroutins:If.vss}

{$INCLUDE :vs_subroutins:Basic.vss}

{$INCLUDE :vs_subroutins:Add_Inc_Dec.vss}

{$INCLUDE :vs_subroutins:KSSErrMsg.vss}

{$INCLUDE :vs_subroutins:Calc.vss}

{$INCLUDE :vs_subroutins:Small.vss}

{$INCLUDE :vs_subroutins:Large.vss}

{$INCLUDE :vs_subroutins:Swap.vss}

{$INCLUDE :vs_subroutins:SwapByOrder.vss}

{$INCLUDE :vs_subroutins:compound_type.vss}

{$INCLUDE :vs_subroutins:GetDefault.vss}

{$INCLUDE :vs_subroutins:Interpolation.vss}

{$INCLUDE :vs_subroutins:Math.vss}

{$INCLUDE :vs_subroutins:Math-Arc.vss}

{$INCLUDE :vs_subroutins:Drawing.vss}

{$INCLUDE :vs_subroutins:Drawing-New.vss}

{$INCLUDE :vs_subroutins:3d-Drawing.vss}

function GetPoints(h :handle): integer;

var

i, n :integer;

begin

closed:= IsPolyClosed(h);

n:= GetVertNum(h);

Allocate pt[-1..n + 2];

for i:= 1 to n do begin{ 点座標の取得 }

GetPolyPt(h, i, pt[i].p.x, pt[i].p.y);

pt[i].p.z:= 0;

pt[i].hasArc:= closed | ((1 < i) & (i < n));

end;

if closed then begin

pt[n+1]:= pt[1]; pt[n+2]:= pt[2]; 

pt[-1]:= pt[n-1]; pt[0]:= pt[n]; 

end;

GetPoints:= n;

end;{GetPoints}

function GetArcCenterAndDir(p9, p0, p1 :vector; var cnt :vector; var dir :integer): boolean;

var

ang :real;

v0, v1 :vector;

result :boolean;

begin

result:= SME2ArcCenterV(p9, p0, p1, cnt);

if result then begin

v0:= p0 - p9;

v1:= p1 - p0;

ang:= AzimuthByVecs(v0, v1);

dir:= Sign(ang);

end

else

dir:= 0;

GetArcCenterAndDir:= result;

end;{GetArcCenterAndDir}

function GetNewPt(i :integer; var p :vector): boolean;

var

ang, rad :real;

p0, p1, pc, pm :vector;

v, v0, v1, vc, vcc, vv :vector;

begin

p0:= pt[i].p; p1:= pt[i+1].p;

pm:= (p0 + p1) / 2;

if pt[i].hasArc then begin

if pt[i].isArc then

v0:= RotVec(UnitVec(pt[i].pc - p0), -pt[i].dir * 90)

else

v0:= UnitVec(p1 - p0);

end;

if pt[i+1].hasArc then begin

if pt[i+1].isArc then

v1:= RotVec(UnitVec(pt[i+1].pc - p0), -pt[i+1].dir * 90)

else

v1:= UnitVec(p1 - p0);

end;

if pt[i].hasArc then

if pt[i+1].hasArc then

v:= VecVec2MidAzimuthVec(v0, v1)

else

v:= v0

else if pt[i+1].hasArc then

v:= v1;

if SVE2ArcCenterV(p0, v, p1, pc) then begin

rad:= Vec2Dist(p0 - pc);

ang:= Vec2Ang(p1 - p0);

vc:= UnitVec(pc - pm);

vcc:= RotVec(vc, -ang);

vv:= RotVec(v, -ang);

p:= pc + Sign(vcc.y) * Sign(vv.y) * vc * rad;

end

else

p:= pm;

d:= Vec2Dist(p - pm);

GetNewPt:= true;

end;{GetNewPt}

begin {main}

hp:= FSActLayer;

h:= hp;

if (h = Nil) | (GetTypeN(h) <> PolygonObj) then GoTo 1000;

iL:= 1;

d:= 4/9 * GetDefaultWS('曲線', '誤差', 1.0, true);

while (iL <= nL) do begin

n:= GetPoints(h);

if n < 3 then GoTo 999;

for i:= 1 to n do begin

if pt[i].hasArc then begin{ 円弧の中心と回転方向を取得 }

pt[i].isArc:= GetArcCenterAndDir(pt[i-1].p, pt[i].p, pt[i+1].p, pt[i].pc, pt[i].dir);

if pt[i].isArc then begin

pt[i].rad:= Vec2Dist(pt[i-1].p - pt[i].pc);

end;

end;

end;

if closed then begin

pt[n+1]:= pt[1]; pt[n+2]:= pt[2]; 

pt[-1]:= pt[n-1]; pt[0]:= pt[n]; 

end;

if closed then

ClosePoly

else

OpenPoly;

BeginPoly;

for i:= 1 to n do begin

AddPointV(pt[i].p);

if closed | (i < n) then begin

if GetNewPt(i, p) then

if pt[i].d < d then

AddPointV(p);

end;

end;

EndPoly;

if h <> hp then

DelObject(h);

h:= LNewObj;

iL:= iL + 1;

end;

999:

SetDSelect(hp);

ReDrawAll;

1000:

end; {main}

Run(PolyToCurve);