描画関数抽象化ver1.1


前回

関連項目

前回のLinerStructure関数を改造することを考える。

//前回のLinerStructure関数
static void LinerStructure(
  PGraphics pg, List<PVector> source, 
  SamplingMethodS sampling, UnittingMethodSi unitting, DrawMethod drawer)
{
  var sub = sampling.exe(source);    
  for(int i = 0; i<sub.size(); i++)
  {
    IDrawingUnit vert = unitting.exe(source,source.indexOf(sub.get(i)));
    drawer.exe(pg, vert);
  }    
}

前回の関数を改造し、各種関数型インターフェースが外部引数を受けるようにする。

SamplingMethodというのはこれからループさせたい座標を選択・形成する関数である。例えばそれが基準となる座標群(Source領域)から望ましい座標を選択するだけであるならば、SamplingMethodの引数はSource領域だけで良い。Source領域は例えばList<PVector>だったりList<List<PVector>>だったりする。

ここで例えば、これからループに用いたい座標群をSamplingMethodによって形成したい場合、それが例えばスプライン関数であったりなどした場合、入力にはスプライン生成用のコントロールポイント(List<PVector>)といくつかの外部引数が必要となる。外部引数は例えばスプライン関数の次数(int)であったり精度だったりする。

この場合SamplingMethodのシグネチャ(戻り値の型と引数の型)は

List<PVector> SamplingMethod(List<PVector>, int, float)

みたいになるであろう。以下では(int,float)をILootingMethodArgsとしてまとめている。

  //SamplingもUnittingもSource領域基準で行う
 static void LinerStructureSource(
   PGraphics pg, List<PVector> source, 
   ISamplingMethodSAA sampling, ILootingMethodArgs sarg,//(s,t,a)
   IUnittingMethodSAIA unitting, ILootingMethodArgs uarg,//(s,i,a)
   IDrawingMethodUAP drawing, ILootingMethodArgs darg)//(pg,u,a)
 {
   var sub = sampling.exe(new SourceAndArgs(source,sarg));    
   for(int i = 0; i<sub.size(); i++)
   {
     IDrawingUnit vert = unitting.exe(
       new SourceAndIndexArgs(source,source.indexOf(sub.get(i)),uarg));
     drawing.exe(pg, new UnitAndPrameter(vert, darg));
   }    
 }   
  //SamplingもUnittingもSource領域とTarget領域をまたがる
 static void LinerStructureSourceAndTarget(
   PGraphics pg, List<PVector> source, List<PVector> target,
   ISamplingMethodSATA sampling, ILootingMethodArgs sarg,//(s,t,a)
   IUnittingMethodSITIA unitting, ILootingMethodArgs uarg,//(s,i,a)
   IDrawingMethodUAP drawing, ILootingMethodArgs darg)//(pg,u,a)
 {
   var sub = sampling.exe(new SourceAndTargetArgs(source,target,sarg));    
   for(int i = 0; i<sub.size(); i++)
   {
     IDrawingUnit vert = unitting.exe(
       new SourceAndTargetIndexArgs(
         source,source.indexOf(sub.get(i)),target,target.indexOf(sub.get(i)),uarg));
     drawing.exe(pg, new UnitAndPrameter(vert, darg));
   }    
 }    

関数型インターフェースのシグネチャ(戻り値の型と引数の型)はまとめ始めるとなんとでもなるし、まとめ過ぎるとキャストがめんどくさいし型を使う意味がなくなるが、おおざっぱに

  interface ISamplingMethod{
   List<PVector> exe(ILootingMethodArgs args);}
 interface ISamplingMethodSATA{
   List<PVector> exe(SourceAndTargetArgs args);}   
  interface ISamplingMethodSAA{
   List<PVector> exe(SourceAndArgs args);}   
      
  interface IUnittingMethod{
   IDrawingUnit exe(ILootingMethodArgs arg);}   
 interface IUnittingMethodSITIA{
   IDrawingUnit exe(SourceAndTargetIndexArgs arg);}     
 interface IUnittingMethodSAIA{
   IDrawingUnit exe(SourceAndIndexArgs arg);}     

  interface IDrawingMethod{
   void exe(PGraphics pg, ILootingMethodArgs args);}   
 interface IDrawingMethodUAP{
   void exe(PGraphics pg, UnitAndPrameter args);}     

状況に合わせて生成される引数まとめ引数。

interface ILootingMethodArgs{}
  static class IndexParameter implements IParams, ILootingMethodArgs{
   int Index;IndexParameter(int index){this.Index=index;}
 }
 static class FloatParameter implements IParams, ILootingMethodArgs{
   float Value;FloatParameter(float value){this.Value=value;}
 }  
 static class MinMaxParameter implements IParams, ILootingMethodArgs{
   float Min;float Max;MinMaxParameter(float min, float max){this.Min=min;this.Max=max;}
 }    
 
 //..........................................................................
 
 static class SourceAndIndexArgs implements ILootingMethodArgs{
   List<PVector> Source;int SourceIndex;ILootingMethodArgs Args;
   SourceAndIndexArgs( List<PVector> source, int index, ILootingMethodArgs args){
     this.Source=source;this.SourceIndex=index;this.Args=args;}
 }
 static class SourceAndArgs implements ILootingMethodArgs{
   List<PVector> Source;ILootingMethodArgs Args;    
   SourceAndArgs(List<PVector> source, ILootingMethodArgs args){
     this.Source=source;this.Args=args;}
 }    
 static class SourceAndTargetArgs implements ILootingMethodArgs{
   List<PVector> Source;List<PVector> Target;ILootingMethodArgs Args;    
   SourceAndTargetArgs(List<PVector> source, List<PVector> target, ILootingMethodArgs args){
     this.Source=source;this.Target=target;this.Args=args;}
 }    
 static class SourceAndTargetIndexArgs implements ILootingMethodArgs{
   List<PVector> Source;int SourceIndex;
   List<PVector> Target;int TargetIndex;
   ILootingMethodArgs Args;    
   SourceAndTargetIndexArgs(List<PVector> source, int s_index, List<PVector> target, int t_index, ILootingMethodArgs args){
     this.Source=source;this.SourceIndex=s_index;this.Target=target;this.TargetIndex=t_index;this.Args=args;}
 }  
 
 //..........................................................................
 
 static class UnitAndPrameter implements ILootingMethodArgs{
   IDrawingUnit Unit;ILootingMethodArgs Args;
   UnitAndPrameter(IDrawingUnit unit, ILootingMethodArgs args){
     this.Unit=unit;this.Args=args;}
 }

本来for文などの内部で使用されるが、今回ひきずりだされることとなった最終的な描画関数。

  static void DrawPointRandomRadius(PGraphics pg, IDrawingUnit unit, float min_radius, float max_radius)
 {
   if(!(unit instanceof Vert1)){return;}
   var vert1 = (Vert1)unit;
   pg.circle(vert1.V0.x, vert1.V0.y, StaticRandom(min_radius, max_radius));
 }  
 
 static void DrawPoint(PGraphics pg, IDrawingUnit unit, float radius)
 {
   if(!(unit instanceof Vert1)){return;}
   var vert1 = (Vert1)unit;
   pg.circle(vert1.V0.x, vert1.V0.y, radius);
 }
static float StaticRandom(){return (float)Math.random();}
static float StaticRandom(float max){return StaticRandom(0,max);}
static float StaticRandom(float min, float max){return (float)(min + (max - min) * Math.random());}

1重のforループは分解したが、今の所2重のforループには対応していない。ゆえに以下のような描画関数もありうる。

  static void DrawNRadial(PGraphics pg, IDrawingUnit unit)
 {
   if(!(unit instanceof VertL)){return;}
   var vertL = (VertL)unit;        
   for(int i = 0; i<vertL.Verts.size(); i++)
   {
     pg.line(vertL.Verts.get(0).x,vertL.Verts.get(0).y,vertL.Verts.get(i).x,vertL.Verts.get(i).y);
   }
 }


実際に組み立てたもの。

  static void DrawPointsRandomRadius(PGraphics pg, List<PVector> source, float min_radius, float max_radius)
 {
   LinerStructureSource(pg, source, 
     ((sata)->SamplingAll(sata.Source)),null,      
     ((saia)->PickNext1(saia.Source,saia.SourceIndex)),null,         
     ((g,uap)->{
       var mm = (MinMaxParameter)(uap.Args);
       DrawPointRandomRadius(g,uap.Unit,mm.Min,mm.Max);}),
     new MinMaxParameter(min_radius,max_radius));              
 }
 
 static void DrawPoints(PGraphics pg, List<PVector> source, float radius)
 {
   LinerStructureSource(pg, source, 
     ((sata)->SamplingAll(sata.Source)),null,      
     ((saia)->PickNext1(saia.Source,saia.SourceIndex)),null,         
     ((g,uap)->DrawPoint(g,uap.Unit,((FloatParameter)(uap.Args)).Value)),new FloatParameter(radius));
 }
  static void DrawNRadialClose(PGraphics pg, List<PVector> source, int n)
 {
   LinerStructureSource(pg, source, 
     ((sata)->SamplingAll(sata.Source)), null,
     ((saia)->PickNextL(saia.Source,saia.SourceIndex,saia.Args)),new IndexParameter(n), 
     ((g,uap)->DrawNRadial(g,uap.Unit)), null); 
 }  

使い方

  strokeWeight(0.01);
 var cyc = SplineMethod.CalcuCyclicSpline(this.Vertices,3,0.1);
 StaticLooting.DrawNRadialClose(this.getGraphics(), cyc, 18);

画像2


描画に際して、最初に与えたSource領域だけから生成可能な座標群もあれば、外部からパラメータを与えなければどうにもならん座標群もある。また、領域から領域に渡って対応関係を結ぶことで得られる座標群もあるであろう。

その例

  static void DrawUnevenness(PGraphics pg, List<PVector> source, List<PVector> target)
 {
   LinerStructureSourceAndTarget(pg,source,target,
     ((sata)->SamplingUnevenness(sata.Source,sata.Target)),null,
     ((satia)->PickTarEvenOdd(satia.Source,satia.SourceIndex,satia.Target,satia.TargetIndex)),null,
     ((g,uap)->DrawLine(g,uap.Unit)),null);
 }
  //smapling      
 static List<PVector>SamplingUnevenness(List<PVector> source, List<PVector> target)
 {
   var ret = new ArrayList<PVector>();
   for(int i = 0; i<source.size(); i++)
   {
     if(target.size()-1<i){break;}                  
     if(i%2==0)
     {
       ret.add(source.get(i).copy());
       ret.add(target.get(i).copy());       
       ret.add(target.get((i+1)%target.size()).copy());         
     }
     else
     {
       ret.add(source.get(i).copy());         
     }        
   }
   return ret;
 }
  static Vert2 PickTarEvenOdd(List<PVector> source, int index1, List<PVector> target, int index2)
 {
   //source領域
   if(0<=index1&&index1%2==0){//偶数なら渡る
     return new Vert2(source.get(index1),target.get((index1)%target.size()));
   }
   else if(0<=index1&&index1%2==1){//奇数なら進む
     return new Vert2(source.get(index1),source.get((index1+1)%source.size()));
   }        
   else if(0<=index2&&index2%2==0){//偶数なら進む
     return new Vert2(target.get(index2),target.get((index2+1)%target.size()));      
   }
   else if(0<=index2&&index2%2==1){//奇数なら渡る
     return new Vert2(target.get(index2),source.get((index2)%source.size()));
   }
   return null;    
 }  

使い方

  var sp1 = SplineMethod.CalcuOpenSpline(List.of(V0,V1,V2),2,0.04);
 var sp2 = SplineMethod.CalcuOpenSpline(List.of(V3,V4,V5),2,0.04);
 StaticLooting.DrawUnevenness(this.getGraphics(),sp1,sp2);

画像1

線形のリスト構造だと意識しづらいが、リスト構造が2つ並ぶとグラフ構造感が露骨に現れてくる。それすなわちどのノードを繋ぐか、どのノードに進むかといったことがコマンド化できるということで、コマンド化できるということはランダムに、あるいは条件付けしてノード間を接続できるということである。次回に続く。

この記事が気に入ったらサポートをしてみませんか?