作者:陳昱(CY)
繼續上一章寫,根據上一章線段存儲的思路,完成線的復制代碼如下:
1
void CSuperCube::CaculateLHelp(int currentDim)
2

{
3
//---------------------------邊計算
4
if (currentDim==0)return;
5
if(currentDim==1)
6
{
7
Lines[0].points1=&Points[0];
8
Lines[0].points2=&Points[DimensionNum];
9
return;
10
}
11
else
12
{
13
//----------------------------------------------------------復制產生的邊
14
int targetStar=LinesCount[currentDim-1];//復制的起始邊
15
int targetEnd=LinesCount[currentDim-1]*2;//復制的結束邊下一條邊
16
for(int i=targetStar;i<targetEnd;++i)
17
{
18
Lines[i].points1=Lines[i-targetStar].points1+DimensionNum*(1<<(currentDim-1));//指針偏移
19
Lines[i].points2=Lines[i-targetStar].points2+DimensionNum*(1<<(currentDim-1));
20
}
21
//------------------------------------------復制部分完成,增加拉伸部分產生的邊
22
targetStar=targetEnd;//拉伸邊存儲起始
23
targetEnd=targetStar+(1<<(currentDim-1));//拉伸邊存儲結束的下一條邊
24
for(int i=targetStar;i<targetEnd;++i)
25
{
26
Lines[i].points1=&Points[(i-targetStar)*DimensionNum];
27
Lines[i].points2=&Points[(i-targetStar*2+targetEnd)*DimensionNum];
28
}
29
}
30
}

2



3

4

5

6



7

8

9

10

11

12



13

14

15

16

17



18

19

20

21

22

23

24

25



26

27

28

29

30

經過查找維基百科,矩陣旋轉采用所說的吉文斯旋轉http://zh.wikipedia.org/w/index.php?title=Givens%E6%97%8B%E8%BD%AC&variant=zh-cn
于是有了點和線的數據,可以初步用OpenGL渲染了!!于是把面的數據生成先拋到一邊,迫不及待完成UI界面、鍵盤交互。
目前為止代碼如下:(由于上一章的代碼沒有debug,難免有些錯誤,上一章的代碼就不修改了,這里貼出正確的代碼,后面加上demo演示)
.h文件:
1
#pragma once
2
#include "mainWindowStyle.h"
3
#include "common/Render/CY_Camera.h"
4
5
class CSuperCube:public CY_Screen
6

{
7
//-----------------------------------------------------------
8
int MaxDim;//維度數量
9
int *PointsCount;
10
int *LinesCount;
11
int *FaceCount;
12
//-----------------------------------------------------------
13
14
float Length;//邊長
15
//-----------------------------------------------------------------------------------------
16
bool isDone;//已經可以渲染的標志
17
18
float *Points;//n維空間中的點(以DimensionNum為一組為一個點坐標,PointNum為點數量,所以該float數組大小為DimensionNum*PointNum)
19
int DimensionNum;
20
int PointNum;
21
22
struct SLine
23
{
24
float *points1;
25
float *points2;
26
SLine()
27
{
28
points1=0;
29
points2=0;
30
}
31
};
32
SLine *Lines;//n維空間中的線(以2個點的x坐標索引為起始)
33
int LineNum;
34
35
struct SFace
36
{
37
float *points1;
38
float *points2;
39
float *points3;
40
float *points4;
41
SFace()
42
{
43
points1=0;
44
points2=0;
45
points3=0;
46
points4=0;
47
}
48
};
49
int FaceNum;
50
SFace *Faces;//n維空間中的面
51
//---------------------------------------------------------------------------------------------
52
//初始化各個維度的立方體中,點、線、面的數量
53
//輸入:maxDim最大維數
54
void InitMaxPLF(int maxDim);
55
56
57
//計算Dim維度下的立方體的點、線、面
58
void CaculatePLF(int Dim);
59
void CaculatePHelp(int currentDim);
60
void CaculateLHelp(int currentDim);
61
void CaculateFHelp(int currentDim);
62
63
64
inline int PtAtIndex(int i)const
65
{
66
return i*DimensionNum;
67
}
68
69
//吉文斯矩陣旋轉,
70
//輸入:dimNum空間維度(>=2,<=15)、point點指針、theta角度、dim1旋轉面的第一個方向、dim2旋轉面的第二個方向(值從1---15)
71
//輸出:point點的坐標值
72
inline void GivensRotateMatrix(int dimNum,float *point,float theta,int dim1,int dim2);
73
74
void Rotate(float theta,int dim1,int dim2);
75
public:
76
CSuperCube();
77
~CSuperCube();
78
79
//-----------------------------------
80
CY_TextBox *DimensionInput;
81
CY_Label *InputLabel;
82
CY_Button *CreateBtn;
83
CY_CheckBox *FaceLineRender;
84
85
CY_Camera theCamera;
86
//------------------------------------
87
88
unsigned long lastTime;
89
unsigned long currentTime;
90
void UpDate();
91
92
void DrawScene();
93
94
void LineRender();
95
void FaceRender();
96
97
98
void OnKeyDown();
99
void OnCreateBtnDown(CY_Controller *);
100
};

2

3

4

5

6



7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23



24

25

26

27



28

29

30

31

32

33

34

35

36



37

38

39

40

41

42



43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65



66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

.cpp文件:
1
#include "Screens.h"
2
#include <math.h>
3
4
5
CSuperCube::CSuperCube():CY_Screen()
6

{
7
isDone=false;
8
Length=50.0f;
9
MaxDim=0;//維度數量
10
11
PointsCount=0;//點數
12
LinesCount=0;//線數
13
FaceCount=0;//面數
14
15
Points=0;//n維空間中的點(以DimensionNum為一組為一個點坐標,PointNum為點數量,所以該float數組大小為DimensionNum*PointNum)
16
DimensionNum=0;
17
PointNum=0;
18
19
Lines=0;//n維空間中的線(以2個點的x坐標索引為起始)
20
LineNum=0;
21
22
Faces=0;
23
FaceNum=0;
24
25
//------------------------------------------------
26
InputLabel=new CY_Label(L"請輸入超立方體維度:",20,20);
27
this->addContent(InputLabel);
28
DimensionInput=new CY_TextBox(160,15,100);
29
DimensionInput->SetNumberic();
30
this->addContent(DimensionInput);
31
CreateBtn=new CY_Button(L"馬上生成~~",windowWidth/2-50,windowHeight-50,100,30);
32
CreateBtn->OnMouseUpEvent.Bind(this,&CSuperCube::OnCreateBtnDown);
33
this->addContent(CreateBtn);
34
FaceLineRender=new CY_CheckBox(400,18,L"線框渲染",true);
35
this->addContent(FaceLineRender);
36
37
38
theCamera.SetTargetPosition(Vector3(0,0,0));
39
theCamera.SetPosition(Vector3(0,0,200));
40
theCamera.SetUpVector(Vector3(0,1,0));
41
42
43
currentTime=GetTickCount();
44
lastTime=currentTime;
45
//--------------------------------------------------
46
47
InitMaxPLF(15);
48
}
49
CSuperCube::~CSuperCube()
50

{
51
if (PointsCount) delete []PointsCount;
52
if(LinesCount) delete[]LinesCount;
53
if(FaceCount)delete[]FaceCount;
54
55
if(Points)delete []Points;
56
if(Lines)delete []Lines;
57
if(Faces)delete []Faces;
58
}
59
//----------------------------------------------------------------------------------------------------------------------------
60
void CSuperCube::InitMaxPLF(int maxDim)
61

{
62
if (MaxDim || maxDim<3 || maxDim>15)
63
return;
64
65
MaxDim=maxDim+1;
66
67
PointsCount=new int[MaxDim];
68
LinesCount=new int[MaxDim];
69
FaceCount=new int[MaxDim];
70
71
int i;
72
73
PointsCount[0]=1;
74
for (i=1;i<MaxDim;++i)
75
PointsCount[i]=PointsCount[i-1]*2;
76
77
LinesCount[0]=0;
78
LinesCount[1]=1;
79
for (i=2;i<MaxDim;++i)
80
LinesCount[i]=LinesCount[i-1]*2+PointsCount[i-1];
81
82
FaceCount[0]=0;
83
FaceCount[1]=0;
84
FaceCount[2]=1;
85
for(i=3;i<MaxDim;++i)
86
FaceCount[i]=FaceCount[i-1]*2+LinesCount[i-1];
87
}
88
inline void CSuperCube::GivensRotateMatrix(int dimNum,float *point,float theta,int dim1,int dim2)
89

{
90
if(dimNum<2 || dimNum>=16 || dim1<0 || dim1>dimNum || dim2<0 ||dim2>dimNum || dim1==dim2)return;
91
92
float temp1=cos(theta);
93
float temp2=sin(theta);
94
float temp=point[dim1]*temp1-point[dim2]*temp2;
95
96
point[dim2]=point[dim1]*temp2+point[dim2]*temp1;
97
point[dim1]=temp;
98
}
99
void CSuperCube::Rotate(float theta,int dim1,int dim2)
100

{
101
for(int i=0;i<PointNum;++i)
102
GivensRotateMatrix(DimensionNum,&Points[i*DimensionNum],theta,dim1,dim2);
103
}
104
//-----------------------------------------------------------------------------------------------------------------------------
105
void CSuperCube::CaculatePHelp(int currentDim)
106

{
107
int i;
108
//----------------------點計算
109
if(currentDim==0)
110
return;
111
else
112
{
113
int targetStart=1<<(currentDim-1);//復制的起始點
114
int targetEnd=1<<currentDim;//復制的結束點下一點
115
for (i=targetStart;i<targetEnd;++i)
116
{
117
int index=DimensionNum*i;//目標點的x坐標索引
118
int source=DimensionNum*targetStart;//來源點的x坐標索引負偏移量
119
for (int j=0;j<currentDim-1;++j)
120
{
121
Points[index+j]=Points[index-source+j];//復制
122
}
123
Points[index+currentDim-1]=Length;//新加的維度設為邊長
124
}
125
}
126
}
127
void CSuperCube::CaculateLHelp(int currentDim)
128

{
129
//---------------------------邊計算
130
if (currentDim==0)return;
131
if(currentDim==1)
132
{
133
Lines[0].points1=&Points[0];
134
Lines[0].points2=&Points[DimensionNum];
135
return;
136
}
137
else
138
{
139
//----------------------------------------------------------復制產生的邊
140
int targetStar=LinesCount[currentDim-1];//復制的起始邊
141
int targetEnd=LinesCount[currentDim-1]*2;//復制的結束邊下一條邊
142
for(int i=targetStar;i<targetEnd;++i)
143
{
144
Lines[i].points1=Lines[i-targetStar].points1+DimensionNum*(1<<(currentDim-1));//指針偏移
145
Lines[i].points2=Lines[i-targetStar].points2+DimensionNum*(1<<(currentDim-1));
146
}
147
//------------------------------------------復制部分完成,增加拉伸部分產生的邊
148
targetStar=targetEnd;//拉伸邊存儲起始
149
targetEnd=targetStar+(1<<(currentDim-1));//拉伸邊存儲結束的下一條邊
150
for(int i=targetStar;i<targetEnd;++i)
151
{
152
Lines[i].points1=&Points[(i-targetStar)*DimensionNum];
153
Lines[i].points2=&Points[(i-targetStar*2+targetEnd)*DimensionNum];
154
}
155
}
156
}
157
void CSuperCube::CaculateFHelp(int currentDim)
158

{
159
160
}
161
void CSuperCube::CaculatePLF(int Dim)
162

{
163
if(!MaxDim || Dim<2 || Dim>=MaxDim)return;
164
165
if(isDone)
166
{
167
delete []Points;
168
delete []Lines;
169
delete []Faces;
170
}
171
172
//-------------------------------------分配好內存空間
173
DimensionNum=Dim;
174
PointNum=PointsCount[DimensionNum];
175
LineNum=LinesCount[DimensionNum];
176
FaceNum=FaceCount[DimensionNum];
177
178
Points=new float[PointNum*DimensionNum];
179
for (int i=0;i<PointNum*DimensionNum;++i)
180
{
181
Points[i]=0;
182
}
183
184
Lines=new SLine[LineNum];
185
Faces=new SFace[FaceNum];
186
187
//-------------------------------------計算值
188
int currentDim=0;
189
while (currentDim<=DimensionNum)
190
{
191
CaculatePHelp(currentDim);
192
CaculateLHelp(currentDim);
193
//CaculateFHelp(currentDim);
194
++currentDim;
195
}
196
//-----------------------------------把n維體中心移到原點
197
for(int i=0;i<DimensionNum*PointNum;++i)
198
{
199
Points[i]-=(Length/2);
200
}
201
}
202
//---------------------------------------------------------------------------------------------------------------------------
203
void CSuperCube::UpDate()
204

{
205
currentTime=GetTickCount();
206
unsigned long dalta=currentTime-lastTime;
207
lastTime=currentTime;
208
209
int i=-1,j=-1;
210
for (i=0;i<DimensionNum;++i)
211
{
212
if(CY_KeyBoard[48+i])
213
break;
214
}
215
for (j=i+1;j<DimensionNum;++j)
216
{
217
if(CY_KeyBoard[48+j])
218
break;
219
}
220
if(i>=0 && j<DimensionNum)//開始旋轉
221
{
222
float theta=dalta*0.0016f;
223
if(CY_KeyBoard[16])//反方向
224
Rotate(-theta,i,j);
225
else
226
Rotate(theta,i,j);
227
}
228
}
229
void CSuperCube::LineRender()
230

{
231
if(!isDone)return;
232
233
glDisable(GL_CULL_FACE);
234
glDisable(GL_LIGHTING);
235
glLineWidth(2.0f);
236
glColor4f(1,1,1,1);
237
for (int i=0;i<LineNum;++i)
238
{
239
glBegin(GL_LINES);
240
glVertex3fv(Lines[i].points1);
241
glVertex3fv(Lines[i].points2);
242
//glVertex3f(30,30,-10);
243
//glVertex3f(-30,30,10);
244
//glVertex3f(30,-30,0);
245
glEnd();
246
}
247
248
}
249
void CSuperCube::FaceRender()
250

{
251
252
}
253
void CSuperCube::DrawScene()
254

{
255
glLoadIdentity();
256
theCamera.ApplyCamera();
257
258
if(FaceLineRender->GetIsCheck())
259
LineRender();
260
else FaceRender();
261
}
262
//---------------------------------------------------------------------------------------------------------------------------------
263
void CSuperCube::OnKeyDown()
264

{
265
if(CY_KeyBoard[27])
266
PostMessage(hwnd,WM_CLOSE,0,0);
267
}
268
void CSuperCube::OnCreateBtnDown(CY_Controller *btn)
269

{
270
const wchar_t *content=DimensionInput->GetText();
271
int Dim=_wtoi(content);
272
CaculatePLF(Dim);
273
isDone=true;
274
}

2

3

4

5

6



7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50



51

52

53

54

55

56

57

58

59

60

61



62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89



90

91

92

93

94

95

96

97

98

99

100



101

102

103

104

105

106



107

108

109

110

111

112



113

114

115

116



117

118

119

120



121

122

123

124

125

126

127

128



129

130

131

132



133

134

135

136

137

138



139

140

141

142

143



144

145

146

147

148

149

150

151



152

153

154

155

156

157

158



159

160

161

162



163

164

165

166



167

168

169

170

171

172

173

174

175

176

177

178

179

180



181

182

183

184

185

186

187

188

189

190



191

192

193

194

195

196

197

198



199

200

201

202

203

204



205

206

207

208

209

210

211



212

213

214

215

216



217

218

219

220

221



222

223

224

225

226

227

228

229

230



231

232

233

234

235

236

237

238



239

240

241

242

243

244

245

246

247

248

249

250



251

252

253

254



255

256

257

258

259

260

261

262

263

264



265

266

267

268

269



270

271

272

273

274

然后是非常狂喜的截圖:











理論上是可以生成任意大于或等于3的任意維度超立方體的,但是int的有效長度只有16,UINT也只有32,所以目前就限制輸入維度是15了。可執行程序在完成面的分布算法后再給出。