// stroke_3D.js // Sunabe kazumichi 2010.2 // http://dp48069596.lolipop.jp/ //scriptographer.2.9.073-arrived/ // PopupDialog of "PLEASE !! UN-Group(Ctrl+Shift+G), UN-CompoundPath" appears in "Zaxis Go !!" button. var excessive_transform_threshold = 2.0; // ---------------------------------------------- function Vector3d(x,y,z){ this.x = x; this.y = y; this.z = z; return this; } // ---------------------------------------------- function Vector3d_clone(){ return new Vector3d(this.x, this.y, this.z); } Vector3d.prototype.clone =Vector3d_clone; // ---------------------------------------------- function Vector3d_add(vt){ this.x += vt.x; this.y += vt.y; this.z += vt.z; return this; } Vector3d.prototype.add =Vector3d_add; // ---------------------------------------------- function Vector3d_sub(vt){ this.x -= vt.x; this.y -= vt.y; this.z -= vt.z; return this; } Vector3d.prototype.sub =Vector3d_sub; // ---------------------------------------------- function Vector3d_xrot(t){ var c = Math.cos(t); var s = Math.sin(t); var y2 = this.y*c - this.z*s; var z2 = this.y*s + this.z*c; this.y = y2; this.z = z2; return this; } Vector3d.prototype.xrot =Vector3d_xrot; // ---------------------------------------------- function Vector3d_yrot(t){ var c = Math.cos(t); var s = Math.sin(t); var x2 = this.x*c + this.z*s; var z2 = - this.x*s + this.z*c; this.x = x2; this.z = z2; return this; } Vector3d.prototype.yrot =Vector3d_yrot; // ---------------------------------------------- function Vector3d_zrot(t){ var c = Math.cos(t); var s = Math.sin(t); var x2 = this.x*c - this.y*s; var y2 = this.x*s + this.y*c; this.x = x2; this.y = y2; return this; } Vector3d.prototype.zrot =Vector3d_zrot; // ---------------------------------------------- function Vector3d_rot(xr, yr, zr){ this.xrot(xr); this.yrot(yr); this.zrot(zr); return this; } Vector3d.prototype.rot =Vector3d_rot; // ---------------------------------------------- function Vector3d_to2dz(f){ this.x = f*this.x/(f-this.z); this.y = f*this.y/(f-this.z); return this; } Vector3d.prototype.to2dz =Vector3d_to2dz; // ---------------------------------------------- var sel, sr, so, so2, inv_radius, vts; var fpnt, global_depth, min_radius; var last_pnt, updated; var hpi = Math.PI / 2; var wpi = Math.PI * 2; var mpi = Math.PI; var p0 = new Point(0,0); var v0 = new Vector3d(0,0,0); // ---------------------------------------------- var min_radius =100; //Fixed : set max( this value, max(selection.width, selection.height)) to virtual sphere's radius var last_pnt = null; var updated = false; var sel = []; var vts = []; // ---------------------------------------------- function onMouseDown(event){ with( activeDocument.activeLayer ){ if( locked || hidden ){ Dialog.alert("please unlock and show the active layer"); return; } } //activeDocument.redraw(); var flen =flenField.text; // focus distance var gdepth=gdepthField.text; // z-axis depth var sheight=sheightField.text; sel = activeDocument.getItems({ type: Path, selected: true }); sr = getArtSetRect(sel); if(sr == null) return; if(so == null) so = sr.center; so2 = -so; inv_radius = 1 / (Math.max(Math.min(sr.width, sr.height) / 2, min_radius)); var ar, j, vt; var opts = {z:0, xr:0, yr:0, zr:0, xor:0, yor:0, zor:0, center:null} var sname, seg; var vectHeight = v0.clone(); vectHeight.z = - gdepth; for(var i=0; i < sel.length; i++){ opts.xor = 0; opts.yor = 0; opts.zor = 0; ar = []; for(j = 0; j < sel[i].segments.length; j++){ seg = sel[i].segments[j]; ar.push([new Vector3d(seg.point.x - so.x, seg.point.y - so.y, 0), new Vector3d(seg.handleIn.x, seg.handleIn.y, 0), new Vector3d(seg.handleOut.x, seg.handleOut.y, 0)]); } getSelfRotationFromName(sel[i], ar, opts); // getRotationFromName(sel[i], opts); if(opts.xor!=0 || opts.yor!=0 || opts.zor!=0){ rotSegDat(ar, opts.xor, opts.yor, opts.zor); } for(var j = 0; j < ar.length; j++){ ar[j][0].add( vectHeight ); } vts.push(ar); } last_pnt = event.point; updated = false; } // ---------------------------------------------- function getSelfRotationFromName(obj, ar, opts){ if( obj instanceof Layer) return; var sname = obj.name; opts.xr = 0; opts.yr = 0; opts.zr = 0; opts.center = obj.bounds.center; oz = 0; // xN: x-axis rotation. uses center of the object itself as origin if(sname.match(/S(-?\d+)/)) { if(xaxis){opts.xr += toRad(RegExp.$1); } if(yaxis){opts.yr += toRad(RegExp.$1); } if(zaxis){opts.zr += toRad(RegExp.$1); } } // actual rotation if(opts.xr!=0 || opts.yr!=0 || opts.zr!=0){ rotSegDat2(ar, opts.xr, opts.yr, opts.zr, opts.center-so, oz); } // N: height ( - global depth) (must be at the beginning of its name) if( sname.match(/^([\d\.-]+)/) && !isNaN(RegExp.$1) ){ var vectHeight = parseFloat(RegExp.$1); for(var j = 0; j < ar.length; j++){ ar[j][0].z += vectHeight; } } if( obj.parent instanceof Item ){ getSelfRotationFromName(obj.parent, ar, opts); } } //---------------------------------------------- function toRad(dg){ return (dg-0)/180*Math.PI; } // ---------------------------------------------- function onMouseDrag(event){ if(last_pnt == null || last_pnt.getDistance(event.point) < 1) return; last_pnt = event.point; var flen =flenField.text; var gdepth=gdepthField.text; var sheight=sheightField.text; if(sel.length < 1 || sr == null) return; var v = (last_pnt - so) * inv_radius; if(v.getDistance(p0) > 0.999) v = v.normalize() * 0.999; // rotation angles var t = Math.asin(v.y); if(isNaN(t)) return; var xr = -t; var yr = Math.asin(v.x / Math.cos(t)); if(isNaN(yr)) return; var zr = 0; var j, vp, seg, pnt; for(var i = 0; i< sel.length; i++){ seg = sel[i].segments; for(j = 0; j < seg.length; j++){ vp = vts[i][j][0]; //.clone(); pnt = view3d(vts[i][j][0], xr, yr, zr, v0, p0) seg[j].point = pnt + so; seg[j].handleIn= view3d(vts[i][j][1], xr, yr, zr, vp, pnt); seg[j].handleOut= view3d(vts[i][j][2], xr, yr, zr, vp, pnt); } } updated = true; } // ---------------------------------------------- function view3d(vt, xr, yr, zr, v2, p){ var flen =flenField.text; var vect = vt.clone().add(v2); vect.rot(xr, yr, zr); vect.to2dz(flen); return new Point(vect.x - p.x, vect.y - p.y); } // ---------------------------------------------- function rotSegDat(ar, xr, yr, zr){ for(var i = 0; i < ar.length; i++){ ar[i][1].add(ar[i][0]); ar[i][2].add(ar[i][0]); ar[i][0].rot(xr, yr, zr); ar[i][1].rot(xr, yr, zr).sub(ar[i][0]); ar[i][2].rot(xr, yr, zr).sub(ar[i][0]); } } // ---------------------------------------------- function rotSegDat2(ar, xr, yr, zr, o, oz){ var vo = new Vector3d(o.x, o.y, oz); for(var i = 0; i < ar.length; i++){ ar[i][0].sub(vo); ar[i][1].add(ar[i][0]); ar[i][2].add(ar[i][0]); ar[i][0].rot(xr, yr, zr).add(vo); ar[i][1].rot(xr, yr, zr).add(vo).sub(ar[i][0]); ar[i][2].rot(xr, yr, zr).add(vo).sub(ar[i][0]); } } // ---------------------------------------------- function onMouseUp(){ resetValues(); } // ---------------------------------------------- function resetValues(){ //sel = null; vts = []; so = null; sr = null; last_pnt = null; updated = false; } // ---------------------------------------------- function getArtSetRect(set){ if(set.length < 1) return null; var tmp_rect = null; for(var i = set.length - 1; i >= 0; i--){ // if there's a path named "origin" in the selection, // set its center as the rotation center if(so == null && set[i].name == "origin"){ so = set[i].bounds.center; if(set.length > 1){ set.remove(i); continue; } } with(set[i].bounds){ if(tmp_rect == null){ tmp_rect = [top, right, bottom, left]; } else { if(top > tmp_rect[0]) tmp_rect[0] = top; if(right > tmp_rect[1]) tmp_rect[1] = right; if(bottom < tmp_rect[2]) tmp_rect[2] = bottom; if(left < tmp_rect[3]) tmp_rect[3] = left; } } } return new Rectangle(new Point(tmp_rect[3], tmp_rect[0]), new Point(tmp_rect[1], tmp_rect[2])); } function dbug(msg){if (true) print('::debug: '+msg); } // ------------------------ Dialog stuff ------------------------ var dialog = new FloatingDialog('tabbed') { title: "Stroke 3D", size: new Size(216, 348), visible: true, onClose: function() { this.destroy(); } }; var estep = new TextPane(dialog){ text:"step:", position:new Point(146, 14) }; var estepField = new TextEdit(dialog){ bounds: [180,12, 25, 20], text:"10" }; var erotate = new TextPane(dialog){ text:"rotate:", position: new Point(136, 38) }; var erotateField = new TextEdit(dialog){ bounds:[180, 36, 25, 20], text:"0" } var escale = new TextPane(dialog){ text:"scale:", position: new Point(142, 58) }; var escaleField = new TextEdit(dialog){ bounds:[180, 56, 25, 20], text:"100" } var emvx = new TextPane(dialog){ text:"movex:", position:new Point(136, 78) }; var emvxField = new TextEdit(dialog){ bounds: [180, 76, 25, 20], text:"0" }; var emvy = new TextPane(dialog){ text:"movey:", position:new Point(136, 98) }; var emvyField = new TextEdit(dialog){ bounds: [180,96, 25, 20], text:"0" }; var bcColor = new TextPane(dialog){ text:"C:", position:new Point(15, 22) }; var bcColorField = new TextEdit(dialog){ bounds: [30, 20, 25, 20], text:"100" }; var bmColor = new TextPane(dialog){ text:"M:", position: new Point(15, 42) }; var bmColorField = new TextEdit(dialog){ bounds:[30, 40, 25, 20], text:"0" } var byColor = new TextPane(dialog){ text:"Y:", position:new Point(15, 62) }; var byColorField = new TextEdit(dialog){ bounds: [30, 60, 25, 20], text:"10" }; var bkColor = new TextPane(dialog){ text:"K:", position: new Point(15, 82) }; var bkColorField = new TextEdit(dialog){ bounds:[30, 80, 25, 20], text:"0" } var bwidth = new TextPane(dialog){ text:"W:", position: new Point(12, 106) }; var bwidthField = new TextEdit(dialog){ bounds:[30, 104, 25, 20], text:"8" }; var fcColor = new TextPane(dialog){ text:"C:", position:new Point(76, 22) }; var fcColorField = new TextEdit(dialog){ bounds: [92, 20, 25, 20], text:"0" }; var fmColor = new TextPane(dialog){ text:"M:", position: new Point(76, 42) }; var fmColorField = new TextEdit(dialog){ bounds:[92, 40, 25, 20], text:"0" } var fyColor = new TextPane(dialog){ text:"Y:", position:new Point(76, 62) }; var fyColorField = new TextEdit(dialog){ bounds: [92, 60, 25, 20], text:"0" }; var fkColor = new TextPane(dialog){ text:"K:", position: new Point(76, 82) }; var fkColorField = new TextEdit(dialog){ bounds:[92, 80, 25, 20], text:"0" } var fwidth = new TextPane(dialog){ text:"W:", position: new Point(72, 106) }; var fwidthField = new TextEdit(dialog){ bounds:[92, 104, 25, 20], text:"0.2" } //------------------------------------ var spcColor = new TextPane(dialog){ text:"C:", position:new Point(15, 170) }; var spcColorField = new TextEdit(dialog){ bounds: [30, 168, 25, 20], text:"70" }; var spmColor = new TextPane(dialog){ text:"M:", position: new Point(15, 190) }; var spmColorField = new TextEdit(dialog){ bounds:[30, 188, 25, 20], text:"0" } var spyColor = new TextPane(dialog){ text:"Y:", position:new Point(15, 210) }; var spyColorField = new TextEdit(dialog){ bounds: [30, 208, 25, 20], text:"0" }; var spkColor = new TextPane(dialog){ text:"K:", position: new Point(15, 230) }; var spkColorField = new TextEdit(dialog){ bounds:[30, 228, 25, 20], text:"0" } var spwidth = new TextPane(dialog){ text:"W:", position: new Point(76, 192) }; var spwidthField = new TextEdit(dialog){ bounds:[96, 190, 25, 20], text:"0.5" }; var sprotate = new TextPane(dialog){ text:"rotate:", position: new Point(136, 172) }; var sprotateField = new TextEdit(dialog){ bounds:[180, 170, 25, 20], text:"20" } var splength = new TextPane(dialog){ text:"length:", position:new Point(136, 192) }; var splengthField = new TextEdit(dialog){ bounds: [180, 190, 25, 20], text:"5" }; var spdist = new TextPane(dialog){ text:"dist:", position: new Point(70, 172) }; var spdistField = new TextEdit(dialog){ bounds:[96, 170, 25, 20], text:"1" } //------------------------------------------------- var flen = new TextPane(dialog){ text:"focal length:", position:new Point(15, 282) }; var flenField = new TextEdit(dialog){ bounds: [88, 280, 25, 20], text:"400" }; var gdepth = new TextPane(dialog){ text:"global depth:", position:new Point(10, 302) }; var gdepthField = new TextEdit(dialog){ bounds: [88, 300, 25, 20], text:"0" }; var sheight = new TextPane(dialog){ text:"z_height:", position:new Point(52, 322) }; var sheightField = new TextEdit(dialog){ bounds: [108, 320, 32, 20], text:"0.5" }; var xaxis=false var xaxisCheck = new CheckBox(dialog){ position: [188, 282], size: [20, 15], visible: true, checked: xaxis, onClick: function () { xaxis = xaxisCheck.checked; } }; var xaxisText = new TextPane(dialog){ text:"x-axis:", position:new Point(148, 282) }; var yaxis=false var yaxisCheck = new CheckBox(dialog){ position: [188, 302], size: [20, 15], visible: true, checked: yaxis, onClick: function () { yaxis = yaxisCheck.checked; } }; var yaxisText = new TextPane(dialog){ text:"y-axis:", position:new Point(148, 302) }; var zaxis=false var zaxisCheck = new CheckBox(dialog){ position: [188, 322], size: [20, 15], visible: true, checked: zaxis, onClick: function () { zaxis = zaxisCheck.checked; } }; var zaxisText = new TextPane(dialog){ text:"z-axis:", position:new Point(148, 322) }; //-------------------------------------------------------------------- var zoffsetButton = new Button(dialog){ text:"Zaxis GO !!", // offset to z -axis position:new Point(134,124), onClick : function(){ var estep=estepField.text; var erotate=erotateField.text; var escale=escaleField.text; var emvx=emvxField.text; var emvy=emvyField.text; var bc=bcColorField.text; var bm=bmColorField.text; var by=byColorField.text; var bk=bkColorField.text; var bwidth=bwidthField.text; var fc=fcColorField.text; var fm=fmColorField.text; var fy=fyColorField.text; var fk=fkColorField.text; var fwidth=fwidthField.text; var sheight=sheightField.text; var stepi=0; var black,cyan,magenta,yellow,alpha var art = new Path(); var shapes = activeDocument.getItems({ type: Path, selected: true }); if (shapes[0].parent instanceof CompoundPath | shapes[0].parent instanceof Group | shapes[0].parent.parent instanceof Group){ var alertMessage = 'PLEASE !! \n\nUN-Group(Ctrl+Shift+G), \nUN-CompoundPath(Ctrl+Shift+Alt+8)'; var dialog = new PopupDialog('alert'); dialog.alert (alertMessage); return; } for (stepi=0; stepi<=estep; stepi++) { for (var j = 0; j