iPad ProとMacBook AirとMac miniがアップデート
アップデートが発表されて即日販売開始されたのは日本時間3/18の夜のことでざいます。コロナウイルスの影響でAppleStoreのリアル店舗が期限を定めずに閉められており、今年のWWDCもネットでの開催に変更された状況下ですから、本来はなんらかの発表会を経て出したかったんじゃないかなぁって思う内容のアップデートです。いや、iPad ProとMacBook Airについてですけど。
iPad Proは筐体本体は2018年のモデルの順当なアップデートという内容ですけど、注目すべきはオプションパーツであるMagic Keyboardですな。
かなり面白い構造になってます。キーボード本体部分にあるキーはシザー構造で打鍵感は未知数ながら見た目は完全にMacBook Proに搭載されているMagic Keyboardです。同じ名前(Magicを冠している)なことから同じ構造だろうと思われ、2018年モデル用のSmart Keyboard Folioから進歩しているだろうと想像されます。まぁそこは「面白い構造部分」ではなく、iPadを宙に浮かせた形で固定するようになった、というところです。これによりiPadの設置角度に自由度が生まれています。またトラックパッドを搭載したことで(またそれを活用する機能がiOSに組み込まれることで)ノートPCライクに使用できるようになり、かつ必要に応じてApple Pencilや指で直接画面を触ってってオペレートが可能になった、ある意味、MacBook系より操作の自由度の上がった物になったと言えるかと思います。iOS内でのユーザに感じさせる自由度がmacOSよりも下である以上、ノートPCを置き換える物にはならないかもだけどMacBook系を選んでいた層の一部を食う可能性はありそうです。現在の最も軽いMacBook Airが1.29kgです。iPad Proの11インチモデル(Wi-Fi + Cellular)は473g、12.9インチは643g。Magic Keyboardがどれぐらいの重さかはわらからないけど、MacBook Airの重量を超えることはないでしょう。
iPad本体としてはLiDARスキャナの搭載が大きいでしょう。いわゆるレーダー?。それがiPhone 11 Proライクに三眼のレンズに見える部分の一つとして配置されているってことでしょか。カメラは二眼でiPhone 11と同じ仕様かなと思ったらちょっと違うようです。広角と超広角レンズって言い方をしているけど、広角側は数字上はiPhone 11と同じながら超広角の方は画素数は減っているけど画角がちょっと広くなってます。iPadのカメラは撮影用というよりARのためのセンサーの一つであるという印象があるので、先のLiDARスキャナと組み合わせて利用するのに最適な内容にしたって性能なのでしょうか? この追加センサーと二眼カメラによる制作方面の面白いソフトウェアが出てくるといいなぁって思います(すぐに思いつくところでは精度の上がった3Dスキャニングソフトウェアとか?)
Apple Pencil部分は従来と変わりはないように見えます。Wi-Fi 6に対応したりストレージ容量が増えたり、それぐらいの内容の変化ですかね。
そんなわけでキーボードと合わせちょっと興味深いモデルチェンジとなったiPad Pro。僕が常用しているiPad Proは2017年6月に登場した10.5インチモデルですんで、今年6月中ばで丸三年使用したということになります。そろそろ買い替えてもいいかなって思ったりするし、さて、どうしたもんか。購入する場合ケースが気になります。2018年モデルと比較して本体サイズにほぼ変化はないと言えますから同じケースを使えるかと思いきやカメラの穴のサイズが決定的に違うため、2018年モデル用に作られたケースを使うとカメラが犠牲になるということですな。もうちょっとサードパーティアクセサリの動向を見て購入時期を判断ですなと思いました。ちなみにiPad Proは即日販売なものの、キーボードの発売は5月らしいですね。
MacBook AirはMacBook Pro 16インチモデルに採用されていた(そして今回のiPad用のキーボードでも採用されている)ものと同じ構造のキーボードに更新されたことと、CPUがIntelの第10世代のものに変更されたのが大きな変化ですね。
キーボードの変化により厚さと重さがちょっと増えていますが使用感としては誤差に収まるんじゃないかなという数字です。一方でCPUは世代が二世代変わり動作周波数が何気に下がっているのですけど、コア数が2コアだったのが4コアになりマルチコアでの性能の向上ともに、シングルコアでも性能が向上しているらしいです。これは接続されるメモリの速度も向上している効果もあるかもしれません。
それ以上にGPU性能が向上しているらしいのが嬉しいかもです。MacBook Airに搭載されるCPUはIce Lakeって呼ばれてますが、そのGPUはIris Plusってのですね。今年1月のIntelのイベントでその性能をアピールしていたようで、AMDのを比較の土俵に乗せておりました。前モデルのMacBook Ariよりも圧倒的に快適になっていると予想されます。Pro Display XDR(6Kモニタ)への出力もサポートされる性能を持つようになったということからもそれが想像されます。
個人的にはMacBook ProのディスクリートGPUを積んだモデルがベストな選択肢なんだけど、そこまでのものを個人で持つ必要がなくなった仕事環境というのがあり(自腹で用意する必要がなくなった)、であれば軽いものが欲しいということがあったりします。なのでちょっと惹かれるものがあるんです。
手持ちのMacBook Pro Late 2016はAppleの下取りサービスで5万円弱で売れるようです。で、MacBook Airはストレージは1TBに抑えてCPU、メモリを最大にするとAppleCareつけて234960円(税込)でした。実質19万円ほどで手に入るかね。迷うわぁ。
Mac miniはがっかりな内容でした。2018年モデルの値下げだけ。(もっとも僕が購入した時から10万円弱安い値段で手に入るようになったというのは1年半を経たとはいえ価値があると言えばそうだけど)。16インチMacBook ProのCPUに仕様を合わせてくれればいいのにね。ためにPro Display XDRへの6K出力はサポートされません(eGPUでUSB-C出力のあるグラフィックカードを経由すれば可能かな)。Mac mini 2014の長年アップデートされない悪夢がまたこないことを祈ります。
点で構成された形状の点の数を減らす
ということで、形状を維持した形で点の数を間引きたくなりました。
38000個の点で構成された線を32000個の点にまで減少させたい時、6000個減らしたいので、38000/6000=6.33...ってことで7個おきに間引けば、一応32000個を下回らせることが可能ですけど、当然形状はよろしくないことになります(事実上あまり気にならないかもしれないけどね)。
ということで、形状をできるだけ維持した形での点を間引く方法はなんだろうと調べると、Douglas and Peuckerアルゴリズムってのが有名なのだそうです。点と点を直線で結んで、それらの間の点とその直線(傾向線)の距離が許容値(ε)より小さい場合にその点を削除し、また次の直線を引いて点との距離が許容値より小さければ点を削除する、というのを削除する点がなくなるまで繰り返す手法は、形状を特徴づける重要な点が維持されるという利点がある一方、見栄えがちょと悪化することがあるようです。まぁでも、単純に機械的に点を削減するよりはマシだろうと考え、この方法を採用する時、Pythonのモジュールとして rdp [GitHub]ってのが配布されていました。普通に pip3 install rdp で入ります。
ちなみに、元の線の曲率を維持するようにして点の数を減らす手法もあり、こっちは形はいい感じになるけど点の位置はオリジナルから外れますね。それをできるモジュールは知りません。OpenCVとか使うのかね?
rdpの基本的な使い方は単純でした。座標の入った配列と許容値 epsilon を指定するだけ。許容値は傾向線からの最小距離ですね。だから値が小さいほど消される点の数は少なくなります。
import svgwrite import xml.etree.ElementTree as ET import numpy as np from rdp import rdp #二つの点の距離を返す def distance( pos0 , pos1 ): p0 = np.array( pos0 ) p1 = np.array( pos1 ) v = p1 - p0 return np.linalg.norm( v ) #元となる形状の入ったsvgファイルを読み込みその座標を配列 poses に入れる。 tree = ET.parse( 'testShape.svg' ) root = tree.getroot() poses = [] for child in root: if 'path' in child.tag: posInfo = child.attrib[ 'd' ] for posStr in posInfo[1:-1].split( 'L' ): pos = posStr.split( ',' ) poses.append( [ float( pos[0] ), float( pos[1] ) ]) #ポイント数を80%に削減することを目標とすることにして、目標のポイント数を設定 newPointsNum = int( len( poses ) * 0.8) baseLen = distance( poses[ 0 ], poses[ 1 ] ) #目標の点数を下回るまで繰り返す。 #ここで問題の rdp モジュールを使ってる i = 1 while True: newPoses = [] eps = baseLen * i * 0.005 #距離の許容値の指定 newPoses = rdp( poses , epsilon = eps ) print( len( newPoses ) ) if len( newPoses ) < newPointsNum: print( '結果 ', len( newPoses ) ) break i += 1 #svgファイルのキャンパスサイズを決めるためのとこ pMaxX = max( poses, key = lambda x: x[ 0 ] ) pMinX = min( poses, key = lambda x: x[ 0 ] ) pMaxY = max( poses, key = lambda x: x[ 1 ] ) pMinY = min( poses, key = lambda x: x[ 1 ] ) w = pMaxX[ 0 ] - pMinX[ 0 ] + pMinX[ 0 ] * 2 h = pMaxY[ 1 ] - pMinY[ 1 ] + pMinY[ 1 ] * 2 #svgファイルへの書き出し。 dwg = svgwrite.Drawing( 'result_testShape.svg' , size=( w , h)) dwg.add( dwg.polygon( points=poses ,stroke='blue', stroke_width=8.0, fill='none', id='オリジナル')) dwg.add( dwg.polygon( points=newPoses ,stroke='red', stroke_width=4.0, fill='none', id='結果' ) ) dwg.save()
得られた結果が以下。青線がオリジナルの形状。赤線が点の数を削減したもの。
目標とする点の数を指定することができないので、とりあえず目標の点の数になるまでループを回しているのだけど、点数が多いと時間がかかりそうでどうしたもんか…。あとepsilonの値を適切に与えるためにもどうしたらいいのか悩みどころっす。
今時のPython 3 インストール
比較的まっさらなmacOS 10.15.3で初めてpython3を実行しようとすると、こんな感じで少しだけ面倒。あれ?Xcodeは入ってんだっけな?
mac $ python3 Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command. mac $ sudo xcodebuild -license Password: You have not agreed to the Xcode license agreements. You must agree to both license agreements below in order to use Xcode. Hit the Enter key to view the license agreements at '/Applications/Xcode.app/Contents/Resources/English.lproj/License.rtf' Xcode and Apple SDKs Agreement PLEASE SCROLL DOWN AND READ ALL OF THE FOLLOWING TERMS AND CONDITIONS (中略)drafted in English. Les parties ont exigé que le présent contrat et tous les documents connexes soient rédigés en anglais. EA1647 8/7/2019 By typing 'agree' you are agreeing to the terms of the software license agreements. Type 'print' to print them or anything else to cancel, [agree, print, cancel] agree You can view the license agreements in Xcode's About Box, or at /Applications/Xcode.app/Contents/Resources/English.lproj/License.rtf mac $ python3 Python 3.7.3 (default, Dec 13 2019, 19:58:14) [Clang 11.0.0 (clang-1100.0.33.17)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>>
IllustarotのSVGインポートで読み込めるポイント数
SVGのパスデータにおいて、一つのパスオブジェクトは何個の点まで持てるかの確認です。ググると32000ってことらしいのですが、その検証です。
import svgwrite import math pointNum = 100 p = "" for i in range( pointNum ): x = 100.0 * math.cos( math.radians( 360.0/float( pointNum ) * i ) ) + 105.0 y = 100.0 * math.sin( math.radians( 360.0/float( pointNum ) * i ) ) + 105.0 if i == 0: p += " M " + str( x ) + " " + str( y ) elif i == pointNum -1: p += " L " + str( x ) + " " + str( y ) + "Z" else: p += " L " + str( x ) + " " + str( y ) dwg = svgwrite.drawing.Drawing( 'test_path.svg' , size=( 210, 210), profile='full' ) path = dwg.path( p ).stroke( color="red" , width=0.5 ).fill( "none" ) dwg.add( path ) dwg.save()
こんな感じのスクリプトで指定したポイント数の円を描いたsvgファイルをIllustratorに読み込みます。この場合、pointNumの値が100なので100ポイントで構成された円が出力されます。
このpointNumの値を32000にしたものはちゃんとIllustratorに読み込めました。しかして、これを32001にするとダメです。上限は32000ということみたいです。
ちなみにですが、先のスクリプトのfor文部分をもう一個追加して、その中の円の半径の指定部分を小さくし、つまり二重の円を描いた時、pointNumが32000でも読み込まれます。ポイント数自体は64000になりますが、一つ一つの円は32000なのでOKってことですね。。
svg経由でこの制限を突破するのは難しいですかねー?
<追記>そもそも、Illustratorの仕様としてパス一個につき32000ポイントしか許容していない疑惑。であるならポイント数を削減する作業が必要になるのだろうけど、隣接する区域のパスとズレが生じそうで嫌やんだよなぁ…。ちなみに先のエントリで話題にした佐渡市の佐渡島本島部分のポイント数は37662でございました。</追記>
ようやく形になった…(追記:なってない)
国土地理院の配布している行政区域データを日本地図を作成する目的でわちゃわちゃいじっておりました。SVGファイルで出力してIllustratorに持っていくのが目的です。
svgwriteやpyprojを使うことでSVGファイルへの出力は随分と前にできていたのだけど、それを直接 Illustrator に読み込むと一部うまく読み込まれないことがあり、困っていたわけです。
これがIllustratorで読み込んだ状態。佐渡市が飛び飛びの線でしか表示されていないように見えるけど、島本体のアウトラインが認識されていない状況です。で、どうにかならないかって時に、
こんな感じで、Affinity Designer ならちゃんと読み込まれたのですよ。ってことでこいつから改めてsvgを書き出してやります。
書き出したsvgファイルをIllustrator で読み込むと
今度はちゃんと読み込まれました。Affinity Desingerがいい感じのSVGファイルにしてくれたってことっすね。ってことで手順はこれで良さそうです。読み込めたと思ったんですけどねぇ。やっぱり同じように島の本島部分の要素が消えてしまいます。佐渡島と対馬に発生中。
<追記>佐渡市の本島のみ、つまり d="" の中に書かれる閉曲線の要素を一つだけにしたものを書き出したのですけど、やっぱりIllustratorでは読み込まれませんでした。そこで、その佐渡市の本島部分だけにしたsvgファイルをテキストエディタで開き、d=""内の一番最後の要素を残し、そこから前のファイル全体から見ると半分までを削除しました。ポイントの数を半減させたってことですね。そしたら読み込まれるわけです。Illustratorがデータを読み込む際、扱えるポイント数に制限があるんじゃないか疑惑が生まれています(そりゃ当然あるだろうけど、Affinity DesignerはもちろんWebブラウザでも読み込める範囲のポイント数でダメになっちゃうの?って思いますけど...もちろんBlenderも読み込める)。
Affinity DesignerからパスをコピペでIllustratorに持っていけるのだけど、佐渡市本島については島の一部が欠けた形でペーストされることからそんな予想をしてみているのですが、実際のとこどうなんでしょう。そしてそうだとするなら回避手段は無い?</追記>
余談ながら、これはテストのために新潟県だけを出したものなのだけど、svgwriteから出力されたSVGファイルは9.9MBで、それを読み込んでAffinity Desginerから書き出されたSVGファイルは2.6MBでした。お互いのファイルを開いてみたところ、Affinity Desinger産のSVGファイルのサイズが小さいのは、有効桁数が少ないのと相対位置で座標が記録されているからのようです。svgは単なるテキストファイルだから、それだけでだいぶサイズが変わってきてしまうわけっすな。
さらに余談ながら、Affinity Designerで開けたからこれで以後の作業を完結してもいいのだけど、自動処理をさせたい時(市町村ごとに違う色を割り当てたいとかしたい時)、現状手動でやらざる得ないってのは困るかなと思いました。
それから、例えば長岡市の内側に見附市の飛び地があるようなのだけど、下図の緑色領域内にある小さな黒線で囲まれた範囲ですね。そこは長岡市単体で見た時、穴になっていて欲しいわけです。
レイヤーパレット上は下図のような感じで、ここの「カーブ」って名前のサブレイヤーを選択して
レイヤー→塗りつぶしモード→交互(奇数-偶数) を選ぶことで穴が開きます。
しかしてレイヤーの構造的に長岡市グループの下にカーブレイヤーがあるもので、いちいちグループを開いてカーブレイヤーを選択しメニューを選ぶって手間を経ないといけないのですよ。長岡市だけならいいけど、当然、その他の市町村にも同様の構造のところはあるので、一括で処理したい。のだけど、グループの子供のカーブレイヤーを一括で選択するのがどうも困難らしいのです。
この辺、Illustratorだとレイヤー全部選択して属性パレットの塗りの奇偶規則を適用ボタンをオンにするだけです。
Affinity Designerで同じようにまとめて選択して適用する楽な方法ってあるんかなぁって思いつつ、Illustratorはよくできているなぁと思いました。
SVGのPath
復習です。SVGはXML言語でsvgであることを宣言するところから始まり、図形要素が指示されたテキストが羅列されていくわけですが、この図形要素部分の復習です。
座標系は左上隅を( 0, 0 )とし、右方向にxプラス、下方向にyプラスとなります。単位は指定しなければ出力デバイスのピクセルに対応しています。
図形要素として長方形である rect、円である circle、楕円であるellipse、直線であるline、と言った形状と、polyline、polygon、path と言った複数の任意の点を与えることで複雑な形状を実現するものとがあります。polylineとpolygonはシンプルです。pointsって属性に座標の羅列を与えればいいだけなので。正方形なら points ="0 0, 1 0, 1 1, 0 1" と4点指定してやる。
問題はpathです。曲線を描けるものだから書き方が複雑です。属性としては d だそうです。ただし d="" の""内に書かれるのは座標を示す数字だけではなくコマンドとそのパラメータが記されます。複雑です。
まず、
M x y もしくは m dx dy
という表記です。これはMove toコマンドだそうで、x y もしくは dx dy は移動させたい位置の絶対座標もしくは直前の点からの相対座標への移動を示しています。
これは点の移動なので、線は引かれません。線を引くためのコマンドは3種類あり
- 直線コマンド
- 曲線コマンド
- 円弧コマンド
ということです。
直線はシンプルです。Line to コマンドで表記は
L x y もしくは l dx dy
となります。現在の点からL もしくは l で指定された点に線を引くというコマンドです(小文字のLの場合、現在の点からの相対位置への移動)。現在の点ってなんだ?って思うけど、
<path d="M10 10 L 90 10 L 95 90 L 5 90 L 10 10"/>
なら、( 10, 10 ) を起点に時計回りに線が引かれて台形が描かれる、つまりは直前に指定された座標が現在の点ですな。ただ、この書き方だと閉じてないパスとなりますので、これは台形だから線を閉じる必要がありましょう。閉じるコマンドは Z もしくは z です。4点目の後ろにZと書くだけ。
<path d="M10 10 L 90 10 L 95 90 L 5 90 Z"/>
結果的には polyline や polygon と同じ形状が描かれるわけですけど、ここに三次ベジェ曲線を表す C や S、二次ベジェ曲線を描くQってのと組み合わせると、少ない点で滑らかかつ複雑な形状を描けるわけですな。ついでに円弧は A を使うそうです。L以外流したのは、現状の個人的な用事ではLがあれば十分だから。
ということで Python のsvgwrite モジュールです。
import svgwrite dwg = svgwrite.drawing.Drawing( 'test_path.svg' , size=( 100, 100), profile='tiny' ) #SVG 1.2 Tiny Profile, use Drawing(profile= 'tiny') #SVG 1.1 Full Profile, use Drawing(profile= 'full') points = [ [ 10.0 , 10.0 ] ,[ 90.0 , 10.0 ], [ 95.0, 90.0 ], [ 5.0, 90.0 ]] p = "" for i in range( len( points ) ): if i == 0: p = "M " + str( points[ i ][ 0 ] ) + " " + str( points[ i ][ 1 ] ) elif i == len( points ) - 1: p += "L " + str( points[ i ][ 0 ] ) + " " + str( points[ i ][ 1 ] ) + " Z" else: p += "L " + str( points[ i ][ 0 ] ) + " " + str( points[ i ][ 1 ] ) path = dwg.path( p ).stroke( color="red" , width=0.5 ).fill( "none" ) dwg.add( path ) dwg.save()
んー、こんなんでいいのだろうか?