C#のDrawRectangleとFillRectangleに関するメモ
前書き
C#でDrawRectangleとFillRectangleを組み合わせて枠付き矩形を描画しようとしたらなんかずれるぞ💢💢ってなってちょっと実験してみた。
実験
x,y=50,60の目安を引いた(金色)。
黒の矩形はDrawRectangleで描画、矩形は(50,50,3,3)で指定。
赤の矩形はDrawRectanglesで描画、矩形は(55F,50F,3F,3F)で指定。
緑の矩形はFillRectangleで描画、矩形は(60,50,3,3)で指定。
すると以下のようになる。なんだこのずれは💢💢
考察
画素の座標が整数か端数に0.5がつくかわからないが、整数だと仮定して話をすることにしよう。 矩形の各値を(x,y,w,h)って呼ぶ。
DrawRectangle(s)は[x,x+w][y,y+h]の矩形を塗るらしい。 一辺はw+1,h+1となるので気持ち悪い。半開区間で設定させてくれ。 ちなみに線の太さが1だからこうなるのであって2にすると[x-1,x+w][y-1,y+h]を塗りだす。
FillRectangleは[x,x+w)*[y,y+h)の矩形を塗りつぶす。 一辺はw,hとなるのできりが良い。
まとめ
Drawの方はあくまで線を引く意識でつくってるのでこうなるのではないか。 外側をきっちりしたいなら線の太さを考えて書くかFillを使うべきなのかもしれない。
あとがき
DrawRectangleは整数座標なのに配列版は小数を許していたり、 線を書くのに使うPenはクラスなのに塗るBrushはインターフェースだったり、 ライブラリに一貫性がなくて非常に気味が悪い。
Visual Studio12.0のカスタムビルドステップについてのつぶやき
内容に入る前に
まじめな内容だと思って検索してこの記事が出てきてしまったらごめんなさい。 代わりにmsdnの「カスタム ビルド ステップの指定」という名前のページでも読むといいです。
バージョン情報
Visual Studio 12.0 (つまりVisual Studio 2013)
動機:「Visual Studio上でcursesを使ったアプリを作りたい!」
cursesっていうのはテキストベーストユーザーインターフェース(TUI)のアプリケーションを作るのにあったら便利なライブラリだそうです。 それを使わない場合、標準出力にエスケープシーケンスの混ざった呪文のような文字列を流さなきゃいけないようです。まあcursesっていう名前もそこから来ているらしいですね。
最初はmingwに入っているcursesのヘッダーとライブラリを無理矢理Visual Studioに入れて動かそうと思ったのですが、 動く形にできなかったので、昔から何度か断念していた「開発環境としてVisual Studioを使いながらコンパイラはgccを使う」ということに挑戦しようとしました。
Visual StudioでのC/C++コンパイル
ソースファイル(.cpp)のプロパティを開くと普通はこんな感じになってます。
ビルドツールが「C/C++ コンパイラ」となっていて、このソースコードがVisual Studio付属のC++コンパイラでコンパイルされることがわかります。 ここをカスタムビルドツールに変えましょう。
カスタムビルドツール
カスタムビルドツールの設定画面を開くとこんな感じです。(ちょっと遊んでます。)
とてもテキトウなことを言うと、makefileのようなものです。 コマンドラインには(多分)コマンドプロンプトで実行するコマンドを書きます。 出力ファイルの記述は実行順やビルドしなおしたときに再実行するかどうかを決めるために必要です。
これから
SRM635
250は整数問題にしてやるやり方とdoubleでやるやり方がありますが、doubleでやると誤差死します。 無理矢理、doubleで通しました。
Level1
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
#include <cmath>
using namespace std;
double eps=0.0000001;
double magic(double x){return(x==0?0:1/x);}
bool dequal(double x,double y){
return abs(x-y)<eps && abs(magic(x)-magic(y))<eps;
}
class SimilarRatingGraph
{
public:
double maxLength(vector <int> date, vector <int> rating){
int N=date.size();
vector<double> t(N-1);
for(int i=0;i<N-1;i++)
t[i]=date[i+1]-date[i];
vector<double> k(N-1);
for(int i=0;i<N-1;i++)
k[i]=(rating[i+1]-rating[i])/t[i];
vector<double> L(N-1);
for(int i=0;i<N-1;i++)
L[i]=sqrt(1+k[i]*k[i])*t[i];
double maxL=0;
for(int i=0;i<N-1;i++)
for(int j=i+1;j<N-1;j++){
double s=(t[i])/(t[j]);
double sum=0;
for(int l=0;l<N-j-1;l++){
if(dequal(k[i+l],k[j+l])&& dequal(t[i+l],t[j+l]*s)){
sum+=max(L[i+l],L[j+l]);
maxL=max(maxL,sum);
}else break;
}
}
return maxL;
}
};
追跡を滑らかにする問題
前書
問題設定だけします。頭をキレイにするためには問題を明らかにすることも大切でしょう。
動機
カメラで追跡するけど、カクカクしないようにしたい。 カクカクしないようにしたいけど、ちゃんと追跡したい。
問題
物体の動きはベクトルx(t)で与えられます。 カメラの動きをベクトルC(t)とします。 x(t) (t<=T)の情報を使ってベクトルC(T)を決めます。
カクカク条件
C(t)の加速度の絶対値の積分が小さくなるようにしたい。 つまり、
∫t |(d/dt)2 C(t)| dt < K
追跡条件
C(t)がx(t)とずれないようにしたい。
どういうx(t)に対してずれないようにしたいかという設定が必要だと思うが、とりあえずx∈Xとする。
x∈Xにおいて任意のベクトル関数y(t)をとってきてyの絶対値の平均が1のときに∫t (C(t)-x(t))y(t) dt=Ο(1) が成り立つ。
くらいが欲しい。
Unityの衝突判定
概説
Unityで、衝突判定をすると言えば、ColliderとRigidbodyを使うという方法があります。ただし、これは無茶がやりづらい仕様になっているので、全部Scriptで管理したい僕は悩んでしました。あるとき、無料のAssetを読んでいると、Physicsを使った衝突判定をしているのを見つけました。「これは便利かもしれない」そう思い、僕はPhysicsを勉強することにしました。
ColliderとRigidbodyを使った衝突判定
正確なことを知りたい場合上を参照。
Rigidbodyは剛体です。Colliderは直訳すると衝突するものですが、意訳すると形状です。 親Game ObjectにRigidbodyをつけて、それ以下のGame ObjectにColliderをつけると、Colliderが他のColliderと接触したというイベントをRigidbodyで受け取れるようになります。
こうして作ったRigidbody Colliderは剛体として物理演算で動きを制御されることになります。
動きをScriptで制御する場合、Kinematic属性(属性という名前は今適当につけた)をRigidbodyにつけます。その代わり、そのRigitbodyは物理演算制御のRigidbody以外との衝突イベントを受け取りません。
ここで注目すべき点は、剛体をScript制御する(言葉面から見ておかしなことをしているのはわかると思う。)とそれら同士の衝突イベントが得られないということです。
Triggerを使った衝突判定(?)
TiggerはColliderの属性の一つです。 Triggerというのは「衝突は検知するけどぶつからないもの」です。 例えば、自動ドアの前にTriggerを設置してキャラクターが自動ドアを通過しようとすると、それを検知してドアをあけるというのが表現できます。
これを衝突判定に使おうとするとどうなるか。どのRigidbodyと衝突したかという情報しか得られません。しょうがないのです。それがTriggerです。
第3の方法
Unityの公式Assetの2D Platformerを読んでみましょう。PlayerControlやEnemyでPhysics2Dというのが出てきています。
いわゆるUtilityクラスで、この中の便利な静的関数を利用するというものです。
交差判定などがありそうな気がします。ぷんぷんします。
これら(あるかどうかはわからない)を使って自分なりの物理演算をしようと思います。
あとがき
僕が横断的な学習を行っていたばかりに、Physicsの関数を使うということに気付かなかった。どの衝突判定のチュートリアルにも書いてあるような基礎的な内容だ。とても反省している。
SRM628Div1
Easy
TLEで落としました。遅いコードを書きすぎてしまった。 一応落ちたコードですが、載せておきます。
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
class DivisorsPower
{
public:
long long powint(long long x,long long y){
long long ret=1;
for(int i=0;i<y;i++)
ret*=x;
return ret;
}
long long root(long long x,long long y){
long long ret=pow(x,1/(long double)y);
if(powint(ret,y)==x)return ret;
if(powint(ret,y)>x)return ret-1;
else return ret+1;
}
long long d(long long x){
int ret=0;
for(int i=1;i<sqrt(x);i++){
if(x%i==0)ret+=2;
}
int sqrtx=sqrt(x);
if(x==sqrtx*sqrtx)
if(x%(int)sqrt(x)==0)ret++;
return ret;
}
long long findArgument(long long n){
long long maxk=ceil(log2(n));
for(long long k=maxk;k>=1;k--){
long long x=root(n,k);
cout<<k<<"\t"<<x<<endl;
if(powint(x,k)==n&&d(x)==k)
return x;
}
return -1;
}
};
Medium
Div1で初めて解けたMediumです。 パーズして最大のXの個数をカウントして、候補をソートして、順番につめるだけ。
#include <vector>
#include <string>
#include <utility>
#include <algorithm>
#include <functional>
Using namespace std;
Class CircuitsConstruction
{
Public:
string circuit;
//count,length
pair<int,int> calc(int top){
if(circuit[top]=='A')
{
auto c1=calc(top+1);
auto c2=calc(c1.second+top+1);
return make_pair(c1.first+c2.first,c1.second+c2.second+1);
}
else if(circuit[top]=='B')
{
auto c1=calc(top+1);
auto c2=calc(c1.second+top+1);
return make_pair(max(c1.first,c2.first),c1.second+c2.second+1);
}
else
{
return make_pair(1,1);
}
}
int maximizeResistance(string strcircuit, vector <int> conductors) {
circuit=strcircuit;
sort(conductors.begin(),conductors.end(),greater<int>());//おっきいじゅん
auto xcount=calc(0).first;
int ret=0;
for(int i=0;i<xcount;i++){
ret+=conductors[i];
}
return ret;
}
};