AI Rotater for CS3
永らく放置してあったのですが、サラリとやっつけちゃいましたのでお知らせ致します。aiRotaterというのはCS5以降のイラストレータに対応するエクステンションパネルです。機能としては選択したブツをこれまた選択したアンカーポイントの接線に揃えるよう回転・配置し直すというものです。地図を作る時の路線に合せて文字を配置する時なんかに威力を発揮するエクステンションパネルです。
今回は都合でパネルの機能を3つのスクリプトに分けました。
まず一つ目です。毎回ダイアログを開くのは簡単な事なのですが、パラメータっていうのは一回決めてしまうと殆どさわりません。そうなると、いちいちダイアログを表示して入力を求めるのは野暮だろうと言う事で、パラメータを入力する部分を切り離しました。
#parameter setter
if ($._rotateParameter==undefined) {
$._rotateParameter = new Object();
$._rotateParameter.offset = 0;
$._rotateParameter.isLft = false;
$._rotateParameter.rst = true;
}
var w = new Window(‘dialog’, “Rotater”, undefined);
var pn = w.add(‘panel’,undefined,’offset’);
var tx = pn.add(‘edittext’,undefined,”,{multiline:false});
tx.characters = 15;
tx.text = $._rotateParameter.offset;
var ck1 = w.add(‘checkbox’,undefined,’Reference leftDirection.’);
ck1.value = $._rotateParameter.isLft;
var ck2 = w.add(‘checkbox’,undefined,’Reset angle before apply.’);
ck2.value = $._rotateParameter.rst;
var bt = w.add(‘button’, undefined , ‘OK’, {name:’ok’});
var cl = w.add(‘button’, undefined, ‘Cancel’, {name:’cancel’});
bt.onClick = function (){
w.close();
$._rotateParameter.offset = Number(tx.text) ;
$._rotateParameter.isLft = ck1.value;
$._rotateParameter.rst = ck2.value;
}
w.show();
ご覧の様にヘルパーオブジェクトに値を保持します。ですからAIを再起動すると保持していたデータは消えてしまいます。ご承知下さい。
ダイアログはこんな感じのが出ますので各パラメータを設定しておきます。
続いて実行部分です。こちらも横用と縦用に分けてあります。
#horizontal rotater
$._aiRotater ={
apply : function (){
if ($._rotateParameter==undefined) {
$._rotateParameter = new Object();
$._rotateParameter.offset = 0;
$._rotateParameter.isLft = true;
$._rotateParameter.rst = true;
alert (‘No preset defined, set default parameter and apply.\nYou can set parameters using rotaterSetParameter.jsx’);
}
var tg = app.selection;
if (tg.length!=2) return;
if ($._aiRotater.isTGP(tg[0])) {
if (!$._aiRotater.getTGP(tg[0])) return;
$._aiRotater.exe(tg[0], $._aiRotater.restoreRotation(tg[1]));
}
else {
if (!$._aiRotater.getTGP(tg[1])) return;
$._aiRotater.exe(tg[1], $._aiRotater.restoreRotation(tg[0]));
}
},
exe : function (a, b){
var angle,idx;
var tgp = $._aiRotater.getTGP(a);
if (tgp.parent.pathPoints.length<2) return;
//$._aiRotater.rotater(b,[0,0],-Math.PI/2);
var ctr = $._aiRotater.getCenter(b);
var diff = [tgp.anchor[0] – ctr[0], tgp.anchor[1] – ctr[1]];
if (!$._aiRotater.isCorner(a.pathPoints[$._aiRotater.getIndex(a)])){
angle = $._aiRotater.getAngle(
tgp.rightDirection[0] – tgp.leftDirection[0],
tgp.rightDirection[1] – tgp.leftDirection[1]);
if (angle>=Math.PI/2) angle -= Math.PI;
if (angle<=-Math.PI/2) angle += Math.PI;
}
else if ($._rotateParameter.isLft&&!$._aiRotater.isSame(tgp.leftDirection,tgp.anchor)){
angle = $._aiRotater.getAngle(
tgp.anchor[0] – tgp.leftDirection[0],
tgp.anchor[1] – tgp.leftDirection[1]);
}
else if (!$._rotateParameter.isLft&&!$._aiRotater.isSame(tgp.rightDirection,tgp.anchor)){
angle = $._aiRotater.getAngle(
tgp.rightDirection[0] – tgp.anchor[0],
tgp.rightDirection[1] – tgp.anchor[1]);
}
else {
idx = $._aiRotater.getIndex(tgp.parent);
if (idx!=0){
if (tgp.parent.PolarityValues==PolarityValues.POSITIVE
||idx==tgp.parent.pathPoints.length-1){
angle = $._aiRotater.getAngle(
tgp.anchor[0] – tgp.parent.pathPoints[idx-1].rightDirection[0],
tgp.anchor[1] – tgp.parent.pathPoints[idx-1].rightDirection[1]);
}
else {
angle = $._aiRotater.getAngle(
tgp.anchor[0] – tgp.parent.pathPoints[idx-1].leftDirection[0],
tgp.anchor[1] – tgp.parent.pathPoints[idx-1].leftDirection[1]);
if (angle>Math.PI/2) angle += Math.PI/2;
}
}
}
$._aiRotater.rotater(b, diff, angle);
},
isSame : function(a,b){
if(a[0]==b[0]&&a[1]==b[1]) return true;
return false;
},
getIndex : function(tg){
for (var i=0;i<tg.pathPoints.length;i++)
if (tg.pathPoints[i].selected==PathPointSelection.ANCHORPOINT)
return i;
return null;
},
rotater : function (tg, df, angle){
var tm = app.getRotationMatrix(angle/Math.PI*180);
tm.mValueTX = df[0] + $._rotateParameter.offset * Math.cos(angle+Math.PI/2);
tm.mValueTY = df[1] + $._rotateParameter.offset * Math.sin(angle+Math.PI/2);
tg.transform(tm,true,true,true,true,1);
},
isTGP : function (obj){
if (obj.typename==”GroupItem”
||obj.typename==”TextFrame”
||obj.typename==”CompoundPathItem”
||obj.typename==”SymbolItem”)
return false;
if (obj.typename==”PathItem”) {
var n = 0;
for (var i=0;i<obj.pathPoints.length;i++){
if(obj.pathPoints[i].selected==PathPointSelection.ANCHORPOINT)
n++;
if (n>1) return false;
}
return true;
}
},
getTGP : function (obj){
var n = 0;
var a;
for (var i=0;i<obj.pathPoints.length;i++){
if(obj.pathPoints[i].selected==PathPointSelection.ANCHORPOINT){
a = obj.pathPoints[i];
n++;
}
if (n>1) return false;
}
return a;
},
getCenter : function (tg){
var tmp = tg.geometricBounds;
return [tmp[0]+(tmp[2]-tmp[0])/2, tmp[1]-(tmp[1]-tmp[3])/2];
},
isCorner : function(pt){
var p= new Array();
p[0] = pt.anchor;
p[1] = pt.leftDirection;
p[2] = pt.rightDirection;
if (p[0][0]==p[1][0]&&p[0][0]==p[2][0]){
if (p[1][1]==p[2][1]) return true;
if (p[0][1]<p[1][1]&&p[0][1]>p[2][1]
||p[0][1]>p[1][1]&&p[0][1]<p[2][1]) return true;
return false;
}
var delta = (p[0][1] – p[1][1]) / (p[0][0] – p[1][0]);
var ofst = p[0][1] – p[0][0] * delta;
var rslt = Math.floor(delta * p[2][0] + ofst) – Math.floor (p[2][1]);
if (rslt==0) return false;
else return true;
},
getAngle : function (x,y){
if (x==0&&y==0) return 0;
return Math.atan2(y, x);
},
restoreRotation : function (tgt){
if (!$._rotateParameter.rst) return tgt;
if (tgt.typename==”PathItem”
||tgt.typename==”CompoundPathItem”
||tgt.typename==”SymbolItem”) return tgt;
var tx;
if (tgt.typename==”TextFrame”) tx = tgt;
else {
if (tgt.textFrames.length<1) return tgt;
tx = tgt.textFrames[0];
}
var tm = app.invertMatrix(tx.matrix);
tm.mValueTX = 0;
tm.mValueTY = 0;
tgt.transform(tm,true,true,true,true,1);
return tgt;
}
}
<tg.pathpoints.length;i++) if="" (tg.pathpoints[i].selected="=PathPointSelection.ANCHORPOINT)" return="" i;="" null;="" },="" rotater="" :="" function="" (tg,="" df,="" angle){="" var="" tm="app.getRotationMatrix(angle/Math.PI*180);" tm.mvaluetx="df[0]" +="" $._rotateparameter.offset="" *="" math.cos(angle+math.pi="" 2);="" tm.mvaluety="df[1]" math.sin(angle+math.pi="" tg.transform(tm,true,true,true,true,1);="" istgp="" (obj){="" (obj.typename="="GroupItem"" ||obj.typename="="TextFrame"" false;="" {="" n="0;" for="" (var="" i="0;i
<p[2][1]) return="" true;="" false;="" }="" var="" delta="(p[0][1]" -="" p[1][1])="" (p[0][0]="" p[1][0]);="" ofst="p[0][1]" p[0][0]="" *="" delta;="" rslt="Math.floor(delta" p[2][0]="" +="" ofst)="" math.floor="" (p[2][1]);="" if="" (rslt="=0)" else="" },="" getangle="" :="" function="" (x,y){="" (x="=0&&y==0)" 0;="" math.atan2(y,="" x);="" restorerotation="" (tgt){="" (!$._rotateparameter.rst)="" tgt;="" (tgt.typename="="PathItem"" ||tgt.typename="="CompoundPathItem"" tx;="" tx="tgt;" {="" (tgt.textframes.length<1)="" tm="app.invertMatrix(tx.matrix);" tm.mvaluetx="0;" tm.mvaluety="0;" tgt.transform(tm,true,true,true,true,1);=""
以下が縦用となります。基本的に横縦での違いは1行コメントアウトするかしないかの違いです。
#vertical rotater
$._aiRotater ={
apply : function (){
if ($._rotateParameter==undefined) {
$._rotateParameter = new Object();
$._rotateParameter.offset = 0;
$._rotateParameter.isLft = true;
$._rotateParameter.rst = true;
alert (‘No preset defined, set default parameter and apply.\nYou can set parameters using rotaterSetParameter.jsx’);
}
var tg = app.selection;
if (tg.length!=2) return;
if ($._aiRotater.isTGP(tg[0])) {
if (!$._aiRotater.getTGP(tg[0])) return;
$._aiRotater.exe(tg[0], $._aiRotater.restoreRotation(tg[1]));
}
else {
if (!$._aiRotater.getTGP(tg[1])) return;
$._aiRotater.exe(tg[1], $._aiRotater.restoreRotation(tg[0]));
}
},
exe : function (a, b){
var angle,idx;
var tgp = $._aiRotater.getTGP(a);
if (tgp.parent.pathPoints.length<2) return;
$._aiRotater.rotater(b,[0,0],-Math.PI/2);
var ctr = $._aiRotater.getCenter(b);
var diff = [tgp.anchor[0] – ctr[0], tgp.anchor[1] – ctr[1]];
if (!$._aiRotater.isCorner(a.pathPoints[$._aiRotater.getIndex(a)])){
angle = $._aiRotater.getAngle(
tgp.rightDirection[0] – tgp.leftDirection[0],
tgp.rightDirection[1] – tgp.leftDirection[1]);
if (angle>=Math.PI/2) angle -= Math.PI;
if (angle<=-Math.PI/2) angle += Math.PI;
}
else if ($._rotateParameter.isLft&&!$._aiRotater.isSame(tgp.leftDirection,tgp.anchor)){
angle = $._aiRotater.getAngle(
tgp.anchor[0] – tgp.leftDirection[0],
tgp.anchor[1] – tgp.leftDirection[1]);
}
else if (!$._rotateParameter.isLft&&!$._aiRotater.isSame(tgp.rightDirection,tgp.anchor)){
angle = $._aiRotater.getAngle(
tgp.rightDirection[0] – tgp.anchor[0],
tgp.rightDirection[1] – tgp.anchor[1]);
}
else {
idx = $._aiRotater.getIndex(tgp.parent);
if (idx!=0){
if (tgp.parent.PolarityValues==PolarityValues.POSITIVE
||idx==tgp.parent.pathPoints.length-1){
angle = $._aiRotater.getAngle(
tgp.anchor[0] – tgp.parent.pathPoints[idx-1].rightDirection[0],
tgp.anchor[1] – tgp.parent.pathPoints[idx-1].rightDirection[1]);
}
else {
angle = $._aiRotater.getAngle(
tgp.anchor[0] – tgp.parent.pathPoints[idx-1].leftDirection[0],
tgp.anchor[1] – tgp.parent.pathPoints[idx-1].leftDirection[1]);
if (angle>Math.PI/2) angle += Math.PI/2;
}
}
}
$._aiRotater.rotater(b, diff, angle);
},
isSame : function(a,b){
if(a[0]==b[0]&&a[1]==b[1]) return true;
return false;
},
getIndex : function(tg){
for (var i=0;i<tg.pathPoints.length;i++)
if (tg.pathPoints[i].selected==PathPointSelection.ANCHORPOINT)
return i;
return null;
},
rotater : function (tg, df, angle){
var tm = app.getRotationMatrix(angle/Math.PI*180);
tm.mValueTX = df[0] + $._rotateParameter.offset * Math.cos(angle+Math.PI/2);
tm.mValueTY = df[1] + $._rotateParameter.offset * Math.sin(angle+Math.PI/2);
tg.transform(tm,true,true,true,true,1);
},
isTGP : function (obj){
if (obj.typename==”GroupItem”
||obj.typename==”TextFrame”
||obj.typename==”CompoundPathItem”
||obj.typename==”SymbolItem”)
return false;
if (obj.typename==”PathItem”) {
var n = 0;
for (var i=0;i<obj.pathPoints.length;i++){
if(obj.pathPoints[i].selected==PathPointSelection.ANCHORPOINT)
n++;
if (n>1) return false;
}
return true;
}
},
getTGP : function (obj){
var n = 0;
var a;
for (var i=0;i<obj.pathPoints.length;i++){
if(obj.pathPoints[i].selected==PathPointSelection.ANCHORPOINT){
a = obj.pathPoints[i];
n++;
}
if (n>1) return false;
}
return a;
},
getCenter : function (tg){
var tmp = tg.geometricBounds;
return [tmp[0]+(tmp[2]-tmp[0])/2, tmp[1]-(tmp[1]-tmp[3])/2];
},
isCorner : function(pt){
var p= new Array();
p[0] = pt.anchor;
p[1] = pt.leftDirection;
p[2] = pt.rightDirection;
if (p[0][0]==p[1][0]&&p[0][0]==p[2][0]){
if (p[1][1]==p[2][1]) return true;
if (p[0][1]<p[1][1]&&p[0][1]>p[2][1]
||p[0][1]>p[1][1]&&p[0][1]<p[2][1]) return true;
return false;
}
var delta = (p[0][1] – p[1][1]) / (p[0][0] – p[1][0]);
var ofst = p[0][1] – p[0][0] * delta;
var rslt = Math.floor(delta * p[2][0] + ofst) – Math.floor (p[2][1]);
if (rslt==0) return false;
else return true;
},
getAngle : function (x,y){
if (x==0&&y==0) return 0;
return Math.atan2(y, x);
},
restoreRotation : function (tgt){
if (!$._rotateParameter.rst) return tgt;
if (tgt.typename==”PathItem”
||tgt.typename==”CompoundPathItem”
||tgt.typename==”SymbolItem”) return tgt;
var tx;
if (tgt.typename==”TextFrame”) tx = tgt;
else {
if (tgt.textFrames.length<1) return tgt;
tx = tgt.textFrames[0];
}
var tm = app.invertMatrix(tx.matrix);
tm.mValueTX = 0;
tm.mValueTY = 0;
tgt.transform(tm,true,true,true,true,1);
return tgt;
}
}
$._aiRotater.apply();
<tg.pathpoints.length;i++) if="" (tg.pathpoints[i].selected="=PathPointSelection.ANCHORPOINT)" return="" i;="" null;="" },="" rotater="" :="" function="" (tg,="" df,="" angle){="" var="" tm="app.getRotationMatrix(angle/Math.PI*180);" tm.mvaluetx="df[0]" +="" $._rotateparameter.offset="" *="" math.cos(angle+math.pi="" 2);="" tm.mvaluety="df[1]" math.sin(angle+math.pi="" tg.transform(tm,true,true,true,true,1);="" istgp="" (obj){="" (obj.typename="="GroupItem"" ||obj.typename="="TextFrame"" false;="" {="" n="0;" for="" (var="" i="0;i
<p[2][1]) return="" true;="" false;="" }="" var="" delta="(p[0][1]" -="" p[1][1])="" (p[0][0]="" p[1][0]);="" ofst="p[0][1]" p[0][0]="" *="" delta;="" rslt="Math.floor(delta" p[2][0]="" +="" ofst)="" math.floor="" (p[2][1]);="" if="" (rslt="=0)" else="" },="" getangle="" :="" function="" (x,y){="" (x="=0&&y==0)" 0;="" math.atan2(y,="" x);="" restorerotation="" (tgt){="" (!$._rotateparameter.rst)="" tgt;="" (tgt.typename="="PathItem"" ||tgt.typename="="CompoundPathItem"" tx;="" tx="tgt;" {="" (tgt.textframes.length<1)="" tm="app.invertMatrix(tx.matrix);" tm.mvaluetx="0;" tm.mvaluety="0;" tgt.transform(tm,true,true,true,true,1);="" $._airotater.apply();
今回、技術的に細かい事は書きませんが、スクリプトをいじる方に見て頂きたい所はマトリクスの取り回しです。イラストレータではこのmatrixについて各種のメソッドが用意されていて、回転角に応じたマトリクスや逆マトリクス等がとても扱いやすくなっています。
最後は3種のスクリプトを圧縮した物を置いておきます。ご利用下さい。個々のスクリプトは単機能ですので、スクリプトランチャーからクリックのみとか、例の物でショートカット割り当てるととても使いやすいかも知れません。