//■二次曲面(quadric surface) // // @textbox1〜5には次のように設定します。 // //   入力項目名 textBox名 初期値 //   ---------------------------------- //   拡散反射係数 textBox1  0.7 //   鏡面反射係数 textBox2  0.4 //   反射率    textBox3  0.4 //   環境光係数  textBox4  0.2 //   屈折率 textBox5  1.03 // // Alabel5は表面色入力用です。 //  Clickイベントハンドラにlabel5_Clickを指定します。 //  また、以下のようにプロパティを設定します。 // // // AutoSize False // BackColor Red // BorderStyle Fixed3D // Text (空文字列) // // Bbotton1〜9にはClickイベントハンドラにそれぞれ // <ボタン名>_Clickを指定します。 // // ボタン名 Textプロパティ //   ------------------------------------ // button1 楕円面 // button2 一葉双曲面 // button3 二葉双曲面 // button4 楕円錐面 // button5 楕円放物面 // button6 双曲放物面 // button7 放物柱面 // button8 楕円柱面 // button9 双曲柱面 // using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing.Drawing2D; namespace quadricSurface { public partial class Form1 : Form { private const float 交点なし = 1E8F; private Image image; private Point org = new Point(); private TMatrix t, it; private Point v0; private float dv; private float size_x; private float size_y; private float[,] z_buff; private float 拡散反射係数, 鏡面反射係数, 環境光係数; private float 反射率, 屈折率; Color 物体色; public Form1() { InitializeComponent(); SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); image = new Bitmap(500, 400); z_buff = new float[image.Width, image.Height]; Graphics g = Graphics.FromImage(image); Brush brush = new SolidBrush(Color.White); g.FillRectangle(brush, 0, 0, image.Width, image.Height); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); e.Graphics.DrawImage(image, 0, 0); } public float len(Point a){ return (float)Math.Sqrt(a.X*a.X+a.Y*a.Y+a.Z*a.Z);} public Point unit(Point a){ return (len(a)==0)?new Point(1,0,0):a/len(a);} public Point unit(float a, float e) { double PIR=Math.PI/180; double aa=a*PIR; double ee=e*PIR; float X=(float)(Math.Cos(aa)*Math.Cos(ee)); float Y=(float)(Math.Sin(aa)*Math.Cos(ee)); float Z=(float)(Math.Sin(ee)); return new Point(X,Y,Z); } public Point unit(float a) { double PIR=Math.PI/180; double aa=a*PIR; float X=(float)Math.Cos(aa); float Y=(float)Math.Sin(aa); float Z=0; return new Point(X,Y,Z); } public static TMatrix scale(float scale_x, float scale_y, float scale_z) { TMatrix m=new TMatrix(); m.t[0,0]=scale_x; m.t[1,1]=scale_y; m.t[2,2]=scale_z; return m; } public static TMatrix scale(Point P){ return scale(P.X, P.Y, P.Z);} public static TMatrix scale(float S){ return scale(S, S, S);} public TMatrix rot_x(float sn, float cs) //X軸を中心に回転 { TMatrix m=new TMatrix(); m.t[1,1]=cs; m.t[1,2]=-sn; m.t[2,1]=sn; m.t[2,2]=cs; return m; } public TMatrix rot_y(float sn, float cs) //Y軸を中心に回転 { TMatrix m=new TMatrix(); m.t[0,0]=cs; m.t[0,2]=sn; m.t[2,0]=-sn; m.t[2,2]=cs; return m; } public TMatrix rot_z(float sn, float cs) //Z軸を中心に回転 { TMatrix m=new TMatrix(); m.t[0,0]=cs; m.t[0,1]=-sn; m.t[1,0]=sn; m.t[1,1]=cs; return m; } public TMatrix rot_x(float r) //X軸を中心に回転 { double PIR=Math.PI/180; return rot_x((float)Math.Sin(r*PIR),(float)Math.Cos(r*PIR)); } public TMatrix rot_y(float r) //Y軸を中心に回転 { double PIR=Math.PI/180; return rot_y((float)Math.Sin(r*PIR),(float)Math.Cos(r*PIR)); } public TMatrix rot_z(float r) //Z軸を中心に回転 { double PIR=Math.PI/180; return rot_z((float)Math.Sin(r*PIR),(float)Math.Cos(r*PIR)); } public TMatrix rotate(Point a, float sn, float cs) //回転変換 { Point P=new Point(a.X, a.Y,0); Point axy=unit(P); Point axz=rot_z(-axy.Y,axy.X)*unit(a); return rot_z(axy.Y, axy.X)*rot_y(-axz.Z,axz.X)*rot_x(sn,cs) *rot_y(axz.Z,axz.X)*rot_z(-axy.Y, axy.X); } public TMatrix rotate(float r) { return rot_z(r);} public TMatrix rotate(Point a, float r) { double PIR=Math.PI/180; return rotate(a,(float)Math.Sin(r*PIR),(float)Math.Cos(r*PIR)); } public TMatrix rotate(Point a, Point b) { float sn=len(unit(a) % unit(b)); if(sn !=0) return rotate(unit(a%b),sn, unit(a)*unit(b)); return new TMatrix(); } public TMatrix rotate(Point n) //ベクトル方向に回転 { Point P = new Point(1,0,0); Point ss = P%unit(n); if(len(ss)==0) ss= new Point(0,0,1); Point s = unit(ss); TMatrix t1 = rot_x(-s.Y,s.Z); TMatrix t3 = rot_x(s.Y,s.Z); Point m = unit(t1*n); TMatrix t2 = rot_z(m.Y, m.X); return t3*t2*t1; } public TMatrix move(float x, float y, float z) { TMatrix m=new TMatrix(); m.t[0,3]=x; m.t[1,3]=y; m.t[2,3]=z; return m; } public TMatrix move(Point P) { return move(P.X, P.Y, P.Z); } public TMatrix perspect(float d) { TMatrix m=new TMatrix(); m.t[2,3]=-d; m.t[3,2]=-1/d; return m; } public TMatrix trans(TMatrix a) { TMatrix c=new TMatrix(); for(int i=0; i<4; i++) for(int j=0; j<4; j++) c.t[i,j]=a.t[j,i]; return c; } public TMatrix inverse(TMatrix a) { float d=0; for(int i=0; i<3; i++) d = d + a.t[0,i]*a.t[1, (i+1)%3]*a.t[2, (i+2) % 3] - a.t[0,i]*a.t[1, (i+2)%3]*a.t[2, (i+1) % 3]; TMatrix b=new TMatrix(); if(d != 0) for(int i=0; i<3; i++) for(int j=0; j<3; j++) b.t[i,j]=(a.t[(j+1)%3,(i+1)%3]*a.t[(j+2)%3, (i+2)%3] -a.t[(j+1)%3,(i+2)%3]*a.t[(j+2)%3, (i+1)%3])/d; for(int i=0; i<3; i++) b.t[i,3]=-a.t[i,3]; return b; } private Surface revolve_z(Line a, int n,float b, float e)//z軸回転によるポリゴンモデル作成 { Surface f=new Surface((a.n-1)*n); TMatrix m0,m1; for(int j=0,t=0;j0.1) { f[0] =move(b.p[0]) *rot_xz(b.p[1]-b.p[0]) *a; f[b.n-1]=move(b.p[b.n-1])*rot_xz(b.p[b.n-1]-b.p[b.n-2])*a; } else { f[0] =move(b.p[0])*rot_xz(b.p[1]-b.p[b.n-4])*a; f[b.n-1]=move(b.p[0])*rot_xz(b.p[3]-b.p[b.n-2])*a; } for(int i=1;i255)R=255; int G=(int)(D1*(double)(CU.G)+D2*255);if(G>255)G=255; int B=(int)(D1*(double)(CU.B)+D2*255);if(B>255)B=255; return Color.FromArgb(R,G,B); } private Color mix(Color C1,double d1,Color C2,double d2) { int R=(int)(d1*(double)(C1.R)+d2*(double)(C2.R));if(R>255)R=255; int G=(int)(d1*(double)(C1.G)+d2*(double)(C2.G));if(G>255)G=255; int B=(int)(d1*(double)(C1.B)+d2*(double)(C2.B));if(B>255)B=255; return Color.FromArgb(R,G,B); } private Color mix(Color C1,double d1,Color C2,double d2,Color C3,double d3) { int R=(int)(d1*(double)(C1.R)+d2*(double)(C2.R)+d3*(double)(C3.R));if(R>255)R=255; int G=(int)(d1*(double)(C1.G)+d2*(double)(C2.G)+d3*(double)(C3.G));if(G>255)G=255; int B=(int)(d1*(double)(C1.B)+d2*(double)(C2.B)+d3*(double)(C3.B));if(B>255)B=255; return Color.FromArgb(R,G,B); } private Color shading(Point V, Point L, Point N, Color CU, double s) { double kd=拡散反射係数, ks=鏡面反射係数, ke=環境光係数; Point RV=L-2*(L*N)*N; //反射方向ベクトル double D1=(-N*L)/(len(N)*len(L));  // 拡散および環境光 if(D1<0)D1=0; D1=kd*s*D1+ke;  double D2=s*ks*((-RV*V))/(len(RV)*len(V));    // 反射 if(D2<0)D2=0; int R=(int)(D1*(double)(CU.R)+D2*255);if(R>255)R=255; int G=(int)(D1*(double)(CU.G)+D2*255);if(G>255)G=255; int B=(int)(D1*(double)(CU.B)+D2*255);if(B>255)B=255; return Color.FromArgb(R,G,B); } private Point 補間(Point p1,Point p2,int a1,int a2)//p1,p2を補間 { return ((a1+a2<1) ?p1: ((a2)*p1+a1*p2)/(a1+a2)); } private Color 色補間(Color c1,Color c2,int a1,int a2)//p1,p2を補間 { int aa=a1+a2; float b1=(float)a1, b2=(float)a2; if(aa<1) return c1; float R1=(float)c1.R, G1=(float)c1.G, B1=(float)c1.B; float R2=(float)c2.R, G2=(float)c2.G, B2=(float)c2.B; return Color.FromArgb((int)((b2*R1+b1*R2)/aa),(int)((b2*G1+b1*G2)/aa),(int)((b2*B1+b1*B2)/aa)); } public Csgm ball(Point s) { Point s2=new Point((s.X==0)?0:1/(s.X*s.X),(s.Y==0)?0:1/(s.Y*s.Y),(s.Z==0)?0:1/(s.Z*s.Z)); //MessageBox.Show("ball X=" +s2.X +" Y=" +s2.Y + " Z=" +s2.Z); return new Csgm(s2, new Point(0,0,0),-1); } public Csgm ball (float r) { return ball(new Point(r,r,r));} private void 直線描画(Hyper Hy,Point p0, Point p1,Color c) { Point a0=screen(p0), a1=screen(p1), P=new Point(0,0,0); int xs=(a1.X-a0.X>0)? 1: -1; int ys=(a1.Y-a0.Y>0)? 1: -1; Bitmap w=new Bitmap(image); double sx=(double)w.Width/(double)size_x; double sy=(double)w.Height/(double)size_y; if(Math.Abs((double)(a0.X-a1.X))>Math.Abs((double)(a0.Y-a1.Y))) { int xst=(int)(a0.X+0.5F), xed=(int)(a1.X+0.5F); float DD=a1.X-a0.X; Point B=new Point(0,0,0); for(int x=xst; x!=xed;x+=xs) { B=a0+(a1-a0)*(x-a0.X)/DD; Point A=world(B); Point V=unit(A-v0), N=new Point(0,0,0); Ray VR=new Ray(v0,V); //視線 if(Hy.hit(VR,ref P,ref N)>len(A-v0)) drawPoint(x, B.Y, c); else drawPoint(x, B.Y, mix(c,0.5, w.GetPixel((int)(sx*(double)x),(int)(sy*(double)B.Y)), 1)); } } else { int yst=(int)(a0.Y+0.5F), yed=(int)(a1.Y+0.5F); float DD=a1.Y-a0.Y; Point B=new Point(0,0,0); for(int y=yst; y!=yed;y+=ys) { B=a0+(a1-a0)*(y-a0.Y)/DD; Point A=world(B); Point V=unit(A-v0), N=new Point(0,0,0); Ray VR=new Ray(v0,V); //視線 if(Hy.hit(VR, ref P, ref N)>len(A-v0)) drawPoint((int)B.X, y, c); else drawPoint(B.X, y, mix(c, 0.5, w.GetPixel((int)(sx*(double)B.X),(int)(sy*(double)y)), 1)); } } } private void 画面クリア(Color c) { SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); Graphics g =Graphics.FromImage(image); Brush brush = new SolidBrush(c); g.FillRectangle(brush, 0, 0, image.Width,image.Height); } private void 曲面表示(Point S2,Point S1,float S0) { Hyper Hy=new Hyper(S2,S1,S0); Color C=物体色, bc=Color.FromArgb(0,0,0); init2D(500,400); origin(250,200); 画面クリア(bc); setview(60,40,3000); Point V0 = v0; //視点 Point L0 = new Point(500,500,500); //照明光 Point V = unit(new Point(0,0,1)-V0), N=new Point(0,0,0), P=new Point(0,0,0); Ray VR = new Ray(V0,V); if(Hy.hit(VR, ref P, ref N)>=交点なし) { if((2*Hy.S2.Z + Hy.S1.Z)>0) { Hy.S2=-Hy.S2; Hy.S1=-Hy.S1; Hy.S0=-Hy.S0;} else if(((2*Hy.S2.Z + Hy.S1.Z)==0)&&((2*Hy.S2.Y + Hy.S1.Y)>0)) { Hy.S2=-Hy.S2; Hy.S1=-Hy.S1; Hy.S0=-Hy.S0;} else if(((2*Hy.S2.Z + Hy.S1.Z)==0)&&((2*Hy.S2.Y + Hy.S1.Y)==0)&&((2*Hy.S2.X + Hy.S1.X)>0)) { Hy.S2=-Hy.S2; Hy.S1=-Hy.S1; Hy.S0=-Hy.S0;} } if(Hy.hit(VR, ref P, ref N)<交点なし)//視線が2次曲面と交わるかどうかの判定 { if(N*V>0) { Hy.S2=-Hy.S2; Hy.S1=-Hy.S1; Hy.S0=-Hy.S0;} } Bitmap w=new Bitmap(image); double sx=(double)w.Width/(double)size_x; double sy=(double)w.Height/(double)size_y; for(int x=0; x0) p=new Point[n];} public Line(Point P0, Point P1) { n=2; p=new Point[n]; p[0]=P0; p[1]=P1;} public Line(Point P0, Point P1, Point P2){ n=3; p=new Point[n]; p[0]=P0; p[1]=P1; p[2]=P2;} public Line(Point P0,Point P1,Point P2,Point P3) { n=4; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;} public Line(Point P0,Point P1,Point P2,Point P3, Point P4) { n=5; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;} public Line(Point P0,Point P1,Point P2,Point P3,Point P4,Point P5) { n=6; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;p[5]=P5;} public Line(Point P0,Point P1,Point P2,Point P3,Point P4,Point P5,Point P6) { n=7; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;p[5]=P5;p[6]=P6;} public Line(Point P0,Point P1,Point P2,Point P3,Point P4,Point P5,Point P6,Point P7) { n=8; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;p[5]=P5;p[6]=P6;p[7]=P7;} public Line(Point P0,Point P1,Point P2,Point P3,Point P4,Point P5,Point P6,Point P7,Point P8) { n=9; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;p[5]=P5;p[6]=P6;p[7]=P7;p[8]=P8;} public Line(Point P0,Point P1,Point P2,Point P3,Point P4,Point P5,Point P6,Point P7,Point P8,Point P9) { n=10;p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;p[5]=P5;p[6]=P6;p[7]=P7;p[8]=P8;p[9]=P9;} public Line(Line b){ n=b.n;if(n>0) p=new Point[n];for(int i=0;i0) p=new Point[n];} public Polygon(Point P0, Point P1){ n=3; p=new Point[n]; p[0]=P0; p[1]=P1; p[2]=P0;} public Polygon(Point P0, Point P1, Point P2){ n=4; p=new Point[n]; p[0]=P0; p[1]=P1; p[2]=P2;p[3]=P0;} public Polygon(Point P0,Point P1,Point P2,Point P3) { n=5; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P0;} public Polygon(Point P0,Point P1,Point P2,Point P3, Point P4) { n=6; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;p[5]=P0;} public Polygon(Point P0,Point P1,Point P2,Point P3,Point P4,Point P5) { n=7; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;p[5]=P5;p[6]=P0;} public Polygon(Point P0,Point P1,Point P2,Point P3,Point P4,Point P5,Point P6) { n=8; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;p[5]=P5;p[6]=P6;p[7]=P0;} public Polygon(Point P0,Point P1,Point P2,Point P3,Point P4,Point P5,Point P6,Point P7) { n=9; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;p[5]=P5;p[6]=P6;p[7]=P7;p[8]=P0;} public Polygon(Point P0,Point P1,Point P2,Point P3,Point P4,Point P5,Point P6,Point P7,Point P8) { n=10; p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;p[5]=P5;p[6]=P6;p[7]=P7;p[8]=P8;p[9]=P0;} public Polygon(Point P0,Point P1,Point P2,Point P3,Point P4,Point P5,Point P6,Point P7,Point P8,Point P9) { n=11;p=new Point[n];p[0]=P0;p[1]=P1;p[2]=P2;p[3]=P3;p[4]=P4;p[5]=P5;p[6]=P6;p[7]=P7;p[8]=P8;p[9]=P9;p[10]=P0;} public Polygon(Point[] a,int 頂点数){ n=頂点数+1;if(n>0) p=new Point[n];for(int i=0;i0){ p=new Point[n];for(int i=0;i0) { p=new Point[n];for(int i=0;i0) p=new Point[n];for(int i=0;i0) p=new Polygon[n];} public Surface(Polygon a) {n=1; p=new Polygon[n];p[0]=a;} public Surface(Surface a) {n=a.n;if (n>0) p=new Polygon[n];for(int i=0;i255)R=255; int G=(int)(D1*(double)(A.c.G)+D2*255);if(G>255)G=255; int B=(int)(D1*(double)(A.c.B)+D2*255);if(B>255)B=255; return Color.FromArgb(R,G,B); } } public class Quad:Point //二次局面 { public int type; //次数 public TMatrix A; //2次係数 public Point B; //1次係数 public float C; //0次係数 public Quad() { type=0; C=0;A=new TMatrix();B=new Point(0,0,0); } public Quad(Point s2, Point s1, float s0) { A=scale(s2);B=s1;C=s0; if (!(s2==new Point(0,0,0))) type=2; else if(!(s1==new Point(0,0,0))) type=1; else type=0; } public bool inner(Point P) { if(type==1)if((P*B + C)<=0) return true;else return false; else if((A*P)*P+this.B*P+C<=0) return true; return false; } public float hit(Ray VR, ref Point P, ref Point N) { Point V0 = VR.o; Point V = VR.d; float t = 1E8F; double ad = 0; if(type ==0) return t; if(type ==1) { t=-(B*V0+C)/(B*V);} else { double a = (A*V)*V, b=(2*A*V0+B)*V, c=(A*V0+B)*V0+C; double d = b*b-4*a*c; if(d<0) return 1E8F; ad=Math.Sqrt(d)/Math.Abs(2*a); t=(float)(-b/(2*a)-ad); if(t<0.5F) t=t+2*(float)ad; } if(t<0.5F) return 1E8F; P=VR.o+t*VR.d; N=unit(2*A*P+B); return t; } public static Quad operator *(TMatrix a,Quad b) { Quad c=b; TMatrix r=inverse(a); Point o=-(a*(new Point(0,0,0))); r.t[0,3]=r.t[1,3]=r.t[2,3]=0; c.A=trans(r)*b.A*r; c.B=trans(r)*b.B+2*c.A*o; c.C=b.C+(c.B-c.A*o)*o; return c; } public static Quad operator -(Quad b) { Quad c=b; c.A=-1*b.A;c.B=-b.B; c.C=-b.C; return c; } static TMatrix scale(float scale_x, float scale_y, float scale_z) { TMatrix m=new TMatrix(); m.t[0,0]=scale_x; m.t[1,1]=scale_y; m.t[2,2]=scale_z; return m; } static TMatrix scale(Point P){ return scale(P.X, P.Y, P.Z);} static TMatrix scale(float S){ return scale(S, S, S);} static TMatrix inverse(TMatrix a) { float d=0; for(int i=0; i<3; i++) d = d + a.t[0,i]*a.t[1, (i+1)%3]*a.t[2, (i+2) % 3] - a.t[0,i]*a.t[1, (i+2)%3]*a.t[2, (i+1) % 3]; TMatrix b=new TMatrix(); if(d != 0) for(int i=0; i<3; i++) for(int j=0; j<3; j++) b.t[i,j]=(a.t[(j+1)%3,(i+1)%3]*a.t[(j+2)%3, (i+2)%3] -a.t[(j+1)%3,(i+2)%3]*a.t[(j+2)%3, (i+1)%3])/d; for(int i=0; i<3; i++) b.t[i,3]=-a.t[i,3]; return b; } static TMatrix trans(TMatrix a) { TMatrix c=new TMatrix(); for(int i=0; i<4; i++) for(int j=0; j<4; j++) c.t[i,j]=a.t[j,i]; return c; } } public class Csgm :Point //Constructive Solid Geometry Model { private const int AND = 1; private const int OR = 2; private const int MINUS = 3; private const float 交点なし= 1E8F; public Csgm c1,c2; public Quad h1; public int op; public Ball BV; public Csgm(){ op=0;h1=new Quad();} public Csgm(Point s2,Point s1,float s0) { h1=new Quad(s2,s1,s0);op=0;} public Csgm(Csgm a,Csgm b, int md) { BV=new Ball(new Point(0,0,0),-1); c1=new Csgm(); c2=new Csgm(); if(md==MINUS){c2 =-b; op=AND;} else {c2 = b; op=md;} c1=a; } public Csgm(Csgm a,Csgm b){ new Csgm(a,b,0);} public Csgm(Csgm a) { BV=a.BV; c1=new Csgm();c2=new Csgm();h1=new Quad(); if(a.op==0) { c1=a.c1;c2=a.c2; } else h1=a.h1; op=a.op; } public Csgm(Csgm a, Ball bv) { BV=bv; c1=new Csgm();c2=new Csgm();h1=new Quad(); if(op==0) { c1=a.c1;c2=a.c2; } else h1=a.h1; op=a.op; } public static Csgm operator *(TMatrix a,Csgm b) { Csgm c=b; if(b.op==0){ c.h1=a*(b.h1);return c;} c.c1=a*(b.c1);c.c2=a*(b.c2); return c; } public static Csgm operator -(Csgm b) { Csgm c=b; if(b.op==0){ c.h1=-(b.h1);return c;} if(b.op==AND) c.op=OR; else if(b.op==OR) c.op=AND; c.c1=-(b.c1);c.c2=-(b.c2); return c; } public static Csgm operator +(Csgm a, Csgm b){return new Csgm(a,b,OR);} public static Csgm operator -(Csgm a, Csgm b){return new Csgm(a,b,MINUS);} public static Csgm operator *(Csgm a, Csgm b){return new Csgm(a,b,AND);} public bool inner(Point P) { if(op==AND) return c1.inner(P) & c2.inner(P); if(op==OR) return c1.inner(P) | c2.inner(P); return h1.inner(P); } public bool outer(Point P){ return !inner(P);} public float hit(Ray VR,ref Point P, ref Point N) { if((BV.r>0) && (BV.hit(VR,ref P,ref N)>=交点なし)) return 交点なし; Point P1=new Point(),P2=new Point(),N1=new Point(),N2=new Point(); double t1,t2; if(op==AND) { Ray V=VR; for(int i=0;i<10;i++) { t1=c1.hit(V, ref P1,ref N1); t2=c2.hit(V, ref P2,ref N2); if(t1>=交点なし && t2>=交点なし) return 交点なし; if(Math.Abs(t1-t2)<0.5) { Point PP=V.o+(float)(Math.Max(t1,t2)+0.5)*V.d; if(c1.inner(PP) && c2.inner(PP)) { P=V.o+(float)(Math.Max(t1,t2))*V.d; N=N1; return len(VR.o-P);} else return 交点なし; } if(t1=交点なし && t2>=交点なし) return 交点なし; if(t1