1 |
#ifndef lint |
2 |
static const char RCSid[] = "$Id: sm.c,v 3.18 2003/06/20 00:25:49 greg Exp $"; |
3 |
#endif |
4 |
/* |
5 |
* sm.c |
6 |
*/ |
7 |
|
8 |
#include <string.h> |
9 |
|
10 |
#include "standard.h" |
11 |
#include "sm_flag.h" |
12 |
#include "sm_list.h" |
13 |
#include "sm_geom.h" |
14 |
#include "sm.h" |
15 |
|
16 |
SM *smMesh = NULL; |
17 |
double smDist_sum=0; |
18 |
|
19 |
#ifdef DEBUG |
20 |
int Tcnt=0,Wcnt=0; |
21 |
#endif |
22 |
/* Each edge extends .372 radians */ |
23 |
static FVECT icosa_verts[162] = |
24 |
{{-0.018096,0.495400,0.868477},{0.018614,-0.554780,0.831789}, |
25 |
{0.850436,0.011329,0.525956},{0.850116,0.048016,-0.524402}, |
26 |
{-0.850116,-0.048016,0.524402},{-0.850436,-0.011329,-0.525956}, |
27 |
{0.495955,0.867825,0.030147},{-0.555329,0.831118,0.029186}, |
28 |
{0.555329,-0.831118,-0.029186},{-0.495955,-0.867825,-0.030147}, |
29 |
{-0.018614,0.554780,-0.831789},{0.018096,-0.495400,-0.868477}, |
30 |
{0.000305,-0.034906,0.999391},{0.489330,0.297837,0.819664}, |
31 |
{0.510900,-0.319418,0.798094},{-0.488835,-0.354308,0.797186}, |
32 |
{-0.510409,0.262947,0.818744},{0.999391,0.034875,0.000914}, |
33 |
{0.791335,0.516672,0.326862},{0.791142,0.538234,-0.290513}, |
34 |
{0.826031,-0.460219,-0.325378},{0.826216,-0.481780,0.291985}, |
35 |
{-0.999391,-0.034875,-0.000914},{-0.826216,0.481780,-0.291985}, |
36 |
{-0.826031,0.460219,0.325378},{-0.791142,-0.538234,0.290513}, |
37 |
{-0.791335,-0.516672,-0.326862},{-0.034911,0.998782,0.034881}, |
38 |
{0.280899,0.801316,0.528194},{-0.337075,0.779739,0.527624}, |
39 |
{-0.337377,0.814637,-0.471746},{0.280592,0.836213,-0.471186}, |
40 |
{0.034911,-0.998782,-0.034881},{-0.280592,-0.836213,0.471186}, |
41 |
{0.337377,-0.814637,0.471746},{0.337075,-0.779739,-0.527624}, |
42 |
{-0.280899,-0.801316,-0.528194},{-0.000305,0.034906,-0.999391}, |
43 |
{0.510409,-0.262947,-0.818744},{0.488835,0.354308,-0.797186}, |
44 |
{-0.510900,0.319418,-0.798094},{-0.489330,-0.297837,-0.819664}, |
45 |
{0.009834,-0.306509,0.951817},{0.268764,-0.186284,0.945021}, |
46 |
{0.275239,-0.454405,0.847207},{-0.009247,0.239357,0.970888}, |
47 |
{0.244947,0.412323,0.877491},{0.257423,0.138235,0.956360}, |
48 |
{0.525850,-0.011345,0.850502},{0.696394,0.160701,0.699436}, |
49 |
{0.707604,-0.160141,0.688223},{-0.268186,0.119892,0.955878}, |
50 |
{-0.274715,0.394186,0.877011},{-0.244420,-0.472542,0.846737}, |
51 |
{-0.256843,-0.204627,0.944542},{-0.525332,-0.048031,0.849541}, |
52 |
{-0.695970,-0.209123,0.686945},{-0.707182,0.111718,0.698149}, |
53 |
{0.961307,0.043084,-0.272090},{0.941300,0.301289,-0.152245}, |
54 |
{0.853076,0.304715,-0.423568},{0.961473,0.024015,0.273848}, |
55 |
{0.853344,0.274439,0.443269},{0.941400,0.289953,0.172315}, |
56 |
{0.831918,0.554570,0.019109},{0.669103,0.719629,0.185565}, |
57 |
{0.669003,0.730836,-0.135332},{0.959736,-0.234941,0.153979}, |
58 |
{0.871472,-0.244526,0.425140},{0.871210,-0.214250,-0.441690}, |
59 |
{0.959638,-0.223606,-0.170573},{0.868594,-0.495213,-0.017555}, |
60 |
{0.717997,-0.671205,-0.184294},{0.718092,-0.682411,0.136596}, |
61 |
{-0.961307,-0.043084,0.272090},{-0.959638,0.223606,0.170573}, |
62 |
{-0.871210,0.214250,0.441690},{-0.961473,-0.024015,-0.273848}, |
63 |
{-0.871472,0.244526,-0.425140},{-0.959736,0.234941,-0.153979}, |
64 |
{-0.868594,0.495213,0.017555},{-0.718092,0.682411,-0.136596}, |
65 |
{-0.717997,0.671205,0.184294},{-0.941400,-0.289953,-0.172315}, |
66 |
{-0.853344,-0.274439,-0.443269},{-0.853076,-0.304715,0.423568}, |
67 |
{-0.941300,-0.301289,0.152245},{-0.831918,-0.554570,-0.019109}, |
68 |
{-0.669003,-0.730836,0.135332},{-0.669103,-0.719629,-0.185565}, |
69 |
{-0.306809,0.951188,0.033302},{-0.195568,0.935038,0.295731}, |
70 |
{-0.463858,0.837300,0.289421},{0.239653,0.970270,0.033802}, |
71 |
{0.403798,0.867595,0.290218},{0.129326,0.946383,0.296031}, |
72 |
{-0.029535,0.831255,0.555106},{0.136603,0.674019,0.725974}, |
73 |
{-0.184614,0.662804,0.725678},{0.129164,0.964728,-0.229382}, |
74 |
{0.403637,0.885733,-0.229245},{-0.464015,0.855438,-0.230036}, |
75 |
{-0.195726,0.953383,-0.229677},{-0.029855,0.867949,-0.495755}, |
76 |
{-0.185040,0.711807,-0.677562},{0.136173,0.723022,-0.677271}, |
77 |
{0.306809,-0.951188,-0.033302},{0.195726,-0.953383,0.229677}, |
78 |
{0.464015,-0.855438,0.230036},{-0.239653,-0.970270,-0.033802}, |
79 |
{-0.403637,-0.885733,0.229245},{-0.129164,-0.964728,0.229382}, |
80 |
{0.029855,-0.867949,0.495755},{-0.136173,-0.723022,0.677271}, |
81 |
{0.185040,-0.711807,0.677562},{-0.129326,-0.946383,-0.296031}, |
82 |
{-0.403798,-0.867595,-0.290218},{0.463858,-0.837300,-0.289421} |
83 |
,{0.195568,-0.935038,-0.295731},{0.029535,-0.831255,-0.555106}, |
84 |
{0.184614,-0.662804,-0.725678},{-0.136603,-0.674019,-0.725974}, |
85 |
{-0.009834,0.306509,-0.951817},{0.256843,0.204627,-0.944542}, |
86 |
{0.244420,0.472542,-0.846737},{0.009247,-0.239357,-0.970888}, |
87 |
{0.274715,-0.394186,-0.877011},{0.268186,-0.119892,-0.955878}, |
88 |
{0.525332,0.048031,-0.849541},{0.707182,-0.111718,-0.698149}, |
89 |
{0.695970,0.209123,-0.686945},{-0.257423,-0.138235,-0.956360}, |
90 |
{-0.244947,-0.412323,-0.877491},{-0.275239,0.454405,-0.847207}, |
91 |
{-0.268764,0.186284,-0.945021},{-0.525850,0.011345,-0.850502}, |
92 |
{-0.707604,0.160141,-0.688223},{-0.696394,-0.160701,-0.699436}, |
93 |
{0.563717,0.692920,0.449538},{0.673284,0.428212,0.602763}, |
94 |
{0.404929,0.577853,0.708603},{0.445959,-0.596198,0.667584}, |
95 |
{0.702960,-0.421213,0.573086},{0.611746,-0.681577,0.401523}, |
96 |
{-0.445543,0.548166,0.707818},{-0.702606,0.380190,0.601498}, |
97 |
{-0.611490,0.651895,0.448456},{-0.563454,-0.722602,0.400456}, |
98 |
{-0.672921,-0.469235,0.571835},{-0.404507,-0.625886,0.666814}, |
99 |
{0.404507,0.625886,-0.666814},{0.672921,0.469235,-0.571835}, |
100 |
{0.563454,0.722602,-0.400456},{0.611490,-0.651895,-0.448456}, |
101 |
{0.702606,-0.380190,-0.601498},{0.445543,-0.548166,-0.707818}, |
102 |
{-0.611746,0.681577,-0.401523},{-0.702960,0.421213,-0.573086}, |
103 |
{-0.445959,0.596198,-0.667584},{-0.404929,-0.577853,-0.708603}, |
104 |
{-0.673284,-0.428212,-0.602763},{-0.563717,-0.692920,-0.449538}}; |
105 |
static int icosa_tris[320][3] = |
106 |
{ {1,42,44},{42,12,43},{44,43,14},{42,43,44},{12,45,47},{45,0,46},{47,46,13}, |
107 |
{45,46,47},{14,48,50},{48,13,49},{50,49,2},{48,49,50},{12,47,43},{47,13,48}, |
108 |
{43,48,14},{47,48,43},{0,45,52},{45,12,51},{52,51,16},{45,51,52},{12,42,54}, |
109 |
{42,1,53},{54,53,15},{42,53,54},{16,55,57},{55,15,56},{57,56,4},{55,56,57}, |
110 |
{12,54,51},{54,15,55},{51,55,16},{54,55,51},{3,58,60},{58,17,59},{60,59,19}, |
111 |
{58,59,60},{17,61,63},{61,2,62},{63,62,18},{61,62,63},{19,64,66},{64,18,65}, |
112 |
{66,65,6},{64,65,66},{17,63,59},{63,18,64},{59,64,19},{63,64,59},{2,61,68}, |
113 |
{61,17,67},{68,67,21},{61,67,68},{17,58,70},{58,3,69},{70,69,20},{58,69,70}, |
114 |
{21,71,73},{71,20,72},{73,72,8},{71,72,73},{17,70,67},{70,20,71},{67,71,21}, |
115 |
{70,71,67},{4,74,76},{74,22,75},{76,75,24},{74,75,76},{22,77,79},{77,5,78}, |
116 |
{79,78,23},{77,78,79},{24,80,82},{80,23,81},{82,81,7},{80,81,82},{22,79,75}, |
117 |
{79,23,80},{75,80,24},{79,80,75},{5,77,84},{77,22,83},{84,83,26},{77,83,84}, |
118 |
{22,74,86},{74,4,85},{86,85,25},{74,85,86},{26,87,89},{87,25,88},{89,88,9}, |
119 |
{87,88,89},{22,86,83},{86,25,87},{83,87,26},{86,87,83},{7,90,92},{90,27,91}, |
120 |
{92,91,29},{90,91,92},{27,93,95},{93,6,94},{95,94,28},{93,94,95},{29,96,98}, |
121 |
{96,28,97},{98,97,0},{96,97,98},{27,95,91},{95,28,96},{91,96,29},{95,96,91}, |
122 |
{6,93,100},{93,27,99},{100,99,31},{93,99,100},{27,90,102},{90,7,101}, |
123 |
{102,101,30},{90,101,102},{31,103,105},{103,30,104},{105,104,10},{103,104,105}, |
124 |
{27,102,99},{102,30,103},{99,103,31},{102,103,99},{8,106,108},{106,32,107}, |
125 |
{108,107,34},{106,107,108},{32,109,111},{109,9,110},{111,110,33},{109,110,111}, |
126 |
{34,112,114},{112,33,113},{114,113,1},{112,113,114},{32,111,107},{111,33,112}, |
127 |
{107,112,34},{111,112,107},{9,109,116},{109,32,115},{116,115,36},{109,115,116}, |
128 |
{32,106,118},{106,8,117},{118,117,35},{106,117,118},{36,119,121},{119,35,120}, |
129 |
{121,120,11},{119,120,121},{32,118,115},{118,35,119},{115,119,36}, |
130 |
{118,119,115},{10,122,124},{122,37,123},{124,123,39},{122,123,124}, |
131 |
{37,125,127},{125,11,126},{127,126,38},{125,126,127},{39,128,130}, |
132 |
{128,38,129},{130,129,3},{128,129,130}, |
133 |
{37,127,123},{127,38,128},{123,128,39},{127,128,123},{11,125,132},{125,37,131}, |
134 |
{132,131,41},{125,131,132},{37,122,134},{122,10,133},{134,133,40}, |
135 |
{122,133,134},{41,135,137},{135,40,136},{137,136,5},{135,136,137}, |
136 |
{37,134,131},{134,40,135}, |
137 |
{131,135,41},{134,135,131},{6,65,94},{65,18,138},{94,138,28},{65,138,94}, |
138 |
{18,62,139},{62,2,49},{139,49,13},{62,49,139},{28,140,97},{140,13,46}, |
139 |
{97,46,0},{140,46,97},{18,139,138},{139,13,140},{138,140,28},{139,140,138}, |
140 |
{1,44,114}, |
141 |
{44,14,141},{114,141,34},{44,141,114},{14,50,142},{50,2,68},{142,68,21}, |
142 |
{50,68,142},{34,143,108},{143,21,73},{108,73,8},{143,73,108},{14,142,141}, |
143 |
{142,21,143},{141,143,34},{142,143,141},{0,52,98},{52,16,144},{98,144,29}, |
144 |
{52,144,98},{16,57,145},{57,4,76},{145,76,24},{57,76,145},{29,146,92}, |
145 |
{146,24,82},{92,82,7},{146,82,92},{16,145,144},{145,24,146},{144,146,29}, |
146 |
{145,146,144},{9,88,110},{88,25,147},{110,147,33},{88,147,110},{25,85,148}, |
147 |
{85,4,56},{148,56,15},{85,56,148},{33,149,113},{149,15,53},{113,53,1}, |
148 |
{149,53,113},{25,148,147},{148,15,149},{147,149,33},{148,149,147},{10,124,105}, |
149 |
{124,39,150},{105,150,31},{124,150,105},{39,130,151},{130,3,60},{151,60,19}, |
150 |
{130,60,151},{31,152,100},{152,19,66},{100,66,6},{152,66,100},{39,151,150}, |
151 |
{151,19,152},{150,152,31},{151,152,150},{8,72,117},{72,20,153},{117,153,35}, |
152 |
{72,153,117},{20,69,154},{69,3,129},{154,129,38},{69,129,154},{35,155,120}, |
153 |
{155,38,126},{120,126,11},{155,126,120},{20,154,153},{154,38,155},{153,155,35}, |
154 |
{154,155,153},{7,81,101},{81,23,156},{101,156,30},{81,156,101},{23,78,157}, |
155 |
{78,5,136},{157,136,40},{78,136,157},{30,158,104},{158,40,133},{104,133,10}, |
156 |
{158,133,104},{23,157,156},{157,40,158},{156,158,30},{157,158,156},{ |
157 |
11,132,121}, |
158 |
{132,41,159},{121,159,36},{132,159,121},{41,137,160},{137,5,84},{160,84,26}, |
159 |
{137,84,160},{36,161,116},{161,26,89},{116,89,9},{161,89,116},{41,160,159}, |
160 |
{160,26,161},{159,161,36},{160,161,159}}; |
161 |
static int icosa_nbrs[320][3] = |
162 |
{{3,208,21},{12,3,20},{14,209,3},{2,0,1},{7,12,17},{202,7,16},{201,13,7}, |
163 |
{6,4,5},{11,212,14},{198,11,13},{197,213,11},{10,8,9},{15,1,4},{9,15,6}, |
164 |
{8,2,15},{14,12,13},{19,224,5},{28,19,4},{30,225,19},{18,16,17},{23,28,1}, |
165 |
{250,23,0},{249,29,23},{22,20,21},{27,228,30},{246,27,29},{245,229,27}, |
166 |
{26,24,25},{31,17,20},{25,31,22},{24,18,31},{30,28,29},{35,261,53},{44,35,52}, |
167 |
{46,262,35},{34,32,33},{39,44,49},{197,39,48},{196,45,39},{38,36,37}, |
168 |
{43,265,46},{193,43,45},{192,266,43},{42,40,41},{47,33,36},{41,47,38}, |
169 |
{40,34,47},{46,44,45},{51,213,37},{60,51,36},{62,214,51},{50,48,49},{55,60,33}, |
170 |
{277,55,32},{276,61,55},{54,52,53},{59,217,62},{273,59,61},{272,218,59}, |
171 |
{58,56,57},{63,49,52},{57,63,54},{56,50,63},{62,60,61},{67,229,85},{76,67,84}, |
172 |
{78,230,67},{66,64,65},{71,76,81},{293,71,80},{292,77,71},{70,68,69}, |
173 |
{75,233,78},{289,75,77},{288,234,75},{74,72,73},{79,65,68},{73,79,70}, |
174 |
{72,66,79},{78,76,77},{83,309,69},{92,83,68},{94,310,83},{82,80,81},{87,92,65}, |
175 |
{245,87,64},{244,93,87},{86,84,85},{91,313,94},{241,91,93},{240,314,91}, |
176 |
{90,88,89},{95,81,84},{89,95,86},{88,82,95},{94,92,93},{99,234,117}, |
177 |
{108,99,116},{110,232,99},{98,96,97},{103,108,113},{192,103,112},{194,109,103}, |
178 |
{102,100,101},{107,226,110},{200,107,109},{202,224,107},{106,104,105}, |
179 |
{111,97,100},{105,111,102},{104,98,111},{110,108,109},{115,266,101}, |
180 |
{124,115,100},{126,264,115},{114,112,113},{119,124,97},{288,119,96}, |
181 |
{290,125,119},{118,116,117},{123,258,126},{296,123,125},{298,256,123}, |
182 |
{122,120,121},{127,113,116},{121,127,118},{120,114,127},{126,124,125}, |
183 |
{131,218,149},{140,131,148},{142,216,131},{130,128,129},{135,140,145}, |
184 |
{240,135,144},{242,141,135},{134,132,133},{139,210,142},{248,139,141}, |
185 |
{250,208,139},{138,136,137},{143,129,132},{137,143,134},{136,130,143}, |
186 |
{142,140,141},{147,314,133},{156,147,132},{158,312,147},{146,144,145}, |
187 |
{151,156,129},{272,151,128},{274,157,151},{150,148,149},{155,306,158}, |
188 |
{280,155,157},{282,304,155},{154,152,153},{159,145,148},{153,159,150}, |
189 |
{152,146,159},{158,156,157},{163,256,181},{172,163,180},{174,257,163}, |
190 |
{162,160,161},{167,172,177},{282,167,176},{281,173,167},{166,164,165}, |
191 |
{171,260,174},{278,171,173},{277,261,171},{170,168,169},{175,161,164}, |
192 |
{169,175,166},{168,162,175},{174,172,173},{179,304,165},{188,179,164}, |
193 |
{190,305,179},{178,176,177},{183,188,161},{298,183,160},{297,189,183}, |
194 |
{182,180,181},{187,308,190},{294,187,189},{293,309,187},{186,184,185}, |
195 |
{191,177,180},{185,191,182},{184,178,191},{190,188,189},{195,101,42}, |
196 |
{204,195,41},{206,102,195},{194,192,193},{199,204,38},{10,199,37},{9,205,199}, |
197 |
{198,196,197},{203,105,206},{6,203,205},{5,106,203},{202,200,201}, |
198 |
{207,193,196},{201,207,198},{200,194,207},{206,204,205},{211,138,0}, |
199 |
{220,211,2}, {222,136,211},{210,208,209},{215,220,8},{48,215,10},{50,221,215}, |
200 |
{214,212,213},{219,130,222}, |
201 |
{56,219,221},{58,128,219},{218,216,217},{223,209,212},{217,223,214}, |
202 |
{216,210,223},{222,220,221},{227,106,16},{236,227,18},{238,104,227}, |
203 |
{226,224,225},{231,236,24},{64,231,26},{66,237,231},{230,228,229}, |
204 |
{235,98,238}, |
205 |
{72,235,237},{74,96,235},{234,232,233},{239,225,228},{233,239,230}, |
206 |
{232,226,239},{238,236,237},{243,133,90},{252,243,89},{254,134,243}, |
207 |
{242,240,241},{247,252,86},{26,247,85},{25,253,247},{246,244,245}, |
208 |
{251,137,254}, |
209 |
{22,251,253},{21,138,251},{250,248,249},{255,241,244},{249,255,246}, |
210 |
{248,242,255},{254,252,253},{259,122,160},{268,259,162},{270,120,259}, |
211 |
{258,256,257},{263,268,168},{32,263,170},{34,269,263},{262,260,261}, |
212 |
{267,114,270},{40,267,269},{42,112,267},{266,264,265},{271,257,260}, |
213 |
{265,271,262},{264,258,271},{270,268,269},{275,149,58},{284,275,57}, |
214 |
{286,150,275},{274,272,273},{279,284,54},{170,279,53},{169,285,279}, |
215 |
{278,276,277},{283,153,286},{166,283,285},{165,154,283},{282,280,281}, |
216 |
{287,273,276},{281,287,278},{280,274,287},{286,284,285},{291,117,74}, |
217 |
{300,291,73},{302,118,291},{290,288,289},{295,300,70},{186,295,69}, |
218 |
{185,301,295},{294,292,293},{299,121,302},{182,299,301},{181,122,299}, |
219 |
{298,296,297},{303,289,292},{297,303,294},{296,290,303},{302,300,301}, |
220 |
{307,154,176},{316,307,178},{318,152,307},{306,304,305},{311,316,184}, |
221 |
{80,311,186},{82,317,311},{310,308,309},{315,146,318},{88,315,317}, |
222 |
{90,144,315},{314,312,313},{319,305,308},{313,319,310},{312,306,319}, |
223 |
{318,316,317}}; |
224 |
|
225 |
|
226 |
#ifdef TEST_DRIVER |
227 |
VIEW Current_View = {0,{0,0,0},{0,0,-1},{0,1,0},60,60,0}; |
228 |
int Pick_cnt =0; |
229 |
int Pick_tri = -1,Picking = FALSE,Pick_samp=-1; |
230 |
FVECT Pick_point[500],Pick_origin,Pick_dir; |
231 |
FVECT Pick_v0[500], Pick_v1[500], Pick_v2[500]; |
232 |
int Pick_q[500]; |
233 |
FVECT P0,P1,P2; |
234 |
FVECT FrustumNear[4],FrustumFar[4]; |
235 |
double dev_zmin=.01,dev_zmax=1000; |
236 |
#endif |
237 |
|
238 |
|
239 |
char * |
240 |
tempbuf(len,resize) /* get a temporary buffer */ |
241 |
unsigned len; |
242 |
int resize; |
243 |
{ |
244 |
static char *tempbuf = NULL; |
245 |
static unsigned tempbuflen = 0; |
246 |
|
247 |
#ifdef DEBUG |
248 |
static int in_use=FALSE; |
249 |
|
250 |
if(len == -1) |
251 |
{ |
252 |
in_use = FALSE; |
253 |
return(NULL); |
254 |
} |
255 |
if(!resize && in_use) |
256 |
{ |
257 |
eputs("Buffer in use:cannot allocate:tempbuf()\n"); |
258 |
return(NULL); |
259 |
} |
260 |
#endif |
261 |
if (len > tempbuflen) { |
262 |
if (tempbuflen > 0) |
263 |
tempbuf = realloc((void *)tempbuf, len); |
264 |
else |
265 |
tempbuf = malloc(len); |
266 |
tempbuflen = tempbuf==NULL ? 0 : len; |
267 |
} |
268 |
#ifdef DEBUG |
269 |
in_use = TRUE; |
270 |
#endif |
271 |
return(tempbuf); |
272 |
} |
273 |
|
274 |
smDir(sm,ps,id) |
275 |
SM *sm; |
276 |
FVECT ps; |
277 |
S_ID id; |
278 |
{ |
279 |
VSUB(ps,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm)); |
280 |
normalize(ps); |
281 |
} |
282 |
|
283 |
smClear_flags(sm,which) |
284 |
SM *sm; |
285 |
int which; |
286 |
{ |
287 |
int i; |
288 |
|
289 |
if(which== -1) |
290 |
for(i=0; i < T_FLAGS;i++) |
291 |
memset(SM_NTH_FLAGS(sm,i), '\0', FLAG_BYTES(SM_MAX_TRIS(sm))); |
292 |
else |
293 |
memset(SM_NTH_FLAGS(sm,which), '\0', FLAG_BYTES(SM_MAX_TRIS(sm))); |
294 |
} |
295 |
|
296 |
/* Given an allocated mesh- initialize */ |
297 |
smInit_mesh(sm) |
298 |
SM *sm; |
299 |
{ |
300 |
/* Reset the triangle counters */ |
301 |
SM_NUM_TRI(sm) = 0; |
302 |
SM_FREE_TRIS(sm) = -1; |
303 |
smClear_flags(sm,-1); |
304 |
} |
305 |
|
306 |
|
307 |
/* Clear the SM for reuse: free any extra allocated memory:does initialization |
308 |
as well |
309 |
*/ |
310 |
smClear(sm) |
311 |
SM *sm; |
312 |
{ |
313 |
smDist_sum = 0; |
314 |
smInit_samples(sm); |
315 |
smInit_locator(sm); |
316 |
smInit_mesh(sm); |
317 |
} |
318 |
|
319 |
/* Allocate and initialize a new mesh with max_verts and max_tris */ |
320 |
int |
321 |
smAlloc_mesh(sm,max_verts,max_tris) |
322 |
SM *sm; |
323 |
int max_verts,max_tris; |
324 |
{ |
325 |
int fbytes,i; |
326 |
|
327 |
fbytes = FLAG_BYTES(max_tris); |
328 |
|
329 |
if(!(SM_TRIS(sm) = (TRI *)malloc(max_tris*sizeof(TRI)))) |
330 |
goto memerr; |
331 |
|
332 |
for(i=0; i< T_FLAGS; i++) |
333 |
if(!(SM_NTH_FLAGS(sm,i)=(int32 *)malloc(fbytes))) |
334 |
goto memerr; |
335 |
|
336 |
SM_MAX_VERTS(sm) = max_verts; |
337 |
SM_MAX_TRIS(sm) = max_tris; |
338 |
|
339 |
smInit_mesh(sm); |
340 |
|
341 |
return(max_tris); |
342 |
memerr: |
343 |
error(SYSTEM, "out of memory in smAlloc_mesh()"); |
344 |
} |
345 |
|
346 |
|
347 |
/* |
348 |
* smAlloc_tri(sm) : Allocate a new mesh triangle |
349 |
* SM *sm; : mesh |
350 |
* |
351 |
* Returns ptr to next available tri |
352 |
*/ |
353 |
int |
354 |
smAlloc_tri(sm) |
355 |
SM *sm; |
356 |
{ |
357 |
int id; |
358 |
|
359 |
/* First check if there are any tris on the free list */ |
360 |
/* Otherwise, have we reached the end of the list yet?*/ |
361 |
if(SM_NUM_TRI(sm) < SM_MAX_TRIS(sm)) |
362 |
return(SM_NUM_TRI(sm)++); |
363 |
if((id = SM_FREE_TRIS(sm)) != -1) |
364 |
{ |
365 |
SM_FREE_TRIS(sm) = T_NEXT_FREE(SM_NTH_TRI(sm,id)); |
366 |
return(id); |
367 |
} |
368 |
|
369 |
error(CONSISTENCY,"smAlloc_tri: no more available triangles\n"); |
370 |
return(INVALID); |
371 |
} |
372 |
|
373 |
|
374 |
smFree_mesh(sm) |
375 |
SM *sm; |
376 |
{ |
377 |
int i; |
378 |
|
379 |
if(SM_TRIS(sm)) |
380 |
free(SM_TRIS(sm)); |
381 |
for(i=0; i< T_FLAGS; i++) |
382 |
if(SM_NTH_FLAGS(sm,i)) |
383 |
free(SM_NTH_FLAGS(sm,i)); |
384 |
} |
385 |
|
386 |
|
387 |
/* |
388 |
* smAlloc(max_samples) : Initialize/clear global sample list for at least |
389 |
* max_samples |
390 |
* int max_samples; |
391 |
* |
392 |
*/ |
393 |
smAlloc(max_samples) |
394 |
register int max_samples; |
395 |
{ |
396 |
unsigned nbytes; |
397 |
register unsigned i; |
398 |
int total_points; |
399 |
int max_tris,n; |
400 |
|
401 |
n = max_samples; |
402 |
/* If this is the first call, allocate sample,vertex and triangle lists */ |
403 |
if(!smMesh) |
404 |
{ |
405 |
if(!(smMesh = (SM *)malloc(sizeof(SM)))) |
406 |
error(SYSTEM,"smAlloc():Unable to allocate memory\n"); |
407 |
memset(smMesh, '\0', sizeof(SM)); |
408 |
} |
409 |
else |
410 |
{ /* If existing structure: first deallocate */ |
411 |
smFree_mesh(smMesh); |
412 |
smFree_samples(smMesh); |
413 |
smFree_locator(smMesh); |
414 |
} |
415 |
|
416 |
/* First allocate at least n samples + extra points:at least enough |
417 |
necessary to form the BASE MESH- Default = 4; |
418 |
*/ |
419 |
SM_SAMP(smMesh) = sAlloc(&n,SM_BASE_POINTS); |
420 |
|
421 |
total_points = n + SM_BASE_POINTS; |
422 |
|
423 |
/* Need enough tris for base mesh, + 2 for each sample, plus extra |
424 |
since triangles are not deleted until added and edge flips (max 4) |
425 |
*/ |
426 |
max_tris = n*2 + SM_BASE_TRIS + 10; |
427 |
/* Now allocate space for mesh vertices and triangles */ |
428 |
max_tris = smAlloc_mesh(smMesh, total_points, max_tris); |
429 |
|
430 |
/* Initialize the structure for point,triangle location. |
431 |
*/ |
432 |
smAlloc_locator(smMesh); |
433 |
} |
434 |
|
435 |
|
436 |
|
437 |
smInit_sm(sm,vp) |
438 |
SM *sm; |
439 |
FVECT vp; |
440 |
{ |
441 |
VCOPY(SM_VIEW_CENTER(sm),vp); |
442 |
smClear(sm); |
443 |
smCreate_base_mesh(sm,SM_DEFAULT); |
444 |
} |
445 |
|
446 |
/* |
447 |
* int |
448 |
* smInit(n) : Initialize/clear data structures for n entries |
449 |
* int n; |
450 |
* |
451 |
* This routine allocates/initializes the sample, mesh, and point-location |
452 |
* structures for at least n samples. |
453 |
* If n is <= 0, then clear data structures. Returns number samples |
454 |
* actually allocated. |
455 |
*/ |
456 |
int |
457 |
smInit(n) |
458 |
register int n; |
459 |
{ |
460 |
int max_vertices; |
461 |
sleep(5); |
462 |
/* If n <=0, Just clear the existing structures */ |
463 |
if(n <= 0) |
464 |
{ |
465 |
#ifdef DEBUG |
466 |
fprintf(stderr,"Tcnt=%d Wcnt = %d, avg = %f\n",Tcnt,Wcnt,(float)Wcnt/Tcnt); |
467 |
#endif |
468 |
smClear(smMesh); |
469 |
return(0); |
470 |
} |
471 |
|
472 |
/* Total mesh vertices includes the sample points and the extra vertices |
473 |
to form the base mesh |
474 |
*/ |
475 |
max_vertices = n + SM_BASE_POINTS; |
476 |
|
477 |
/* If the current mesh contains enough room, clear and return */ |
478 |
if(smMesh && (max_vertices <= SM_MAX_VERTS(smMesh)) && SM_MAX_SAMP(smMesh) <= |
479 |
n && SM_MAX_POINTS(smMesh) <= max_vertices) |
480 |
{ |
481 |
smClear(smMesh); |
482 |
return(SM_MAX_SAMP(smMesh)); |
483 |
} |
484 |
/* Otherwise- mesh must be allocated with the appropriate number of |
485 |
samples |
486 |
*/ |
487 |
smAlloc(n); |
488 |
|
489 |
#ifdef DEBUG |
490 |
fprintf(stderr,"smInit: allocating room for %d samples\n", |
491 |
SM_MAX_SAMP(smMesh)); |
492 |
#endif |
493 |
return(SM_MAX_SAMP(smMesh)); |
494 |
} |
495 |
|
496 |
|
497 |
smLocator_apply(sm,v0,v1,v2,func,n) |
498 |
SM *sm; |
499 |
FVECT v0,v1,v2; |
500 |
FUNC func; |
501 |
int n; |
502 |
{ |
503 |
STREE *st; |
504 |
FVECT tri[3]; |
505 |
|
506 |
st = SM_LOCATOR(sm); |
507 |
|
508 |
VSUB(tri[0],v0,SM_VIEW_CENTER(sm)); |
509 |
VSUB(tri[1],v1,SM_VIEW_CENTER(sm)); |
510 |
VSUB(tri[2],v2,SM_VIEW_CENTER(sm)); |
511 |
stVisit(st,tri,func,n); |
512 |
|
513 |
} |
514 |
|
515 |
/* |
516 |
* QUADTREE |
517 |
* insert_samp(argptr,root,qt,parent,q0,q1,q2,bc,scale,rev,f,n,doneptr) |
518 |
* Callback function called from quadtree traversal when leaf is reached |
519 |
* int *argptr; :ptr to sample id number |
520 |
* int root; :quadtree root from which traversal started |
521 |
* QUADTREE qt,parent; :current quadtree node and its parent |
522 |
* BCOORD q0[3],q1[3],q2[3],bc[3]; :barycentric coordinates of the current |
523 |
* quadtree node (q0,q1,q2) and sample (bc) |
524 |
* unsigned int scale,rev; :scale factor relative to which level at in |
525 |
* tree, rev indicates if traversed of child 3 |
526 |
* FUNC f; :function structure so can recurse |
527 |
* int n,*doneptr; :n indicates which level at in quadtree, and |
528 |
* doneptr can be set to indicate whether nbr |
529 |
* sample has been found |
530 |
*/ |
531 |
QUADTREE |
532 |
insert_samp(argptr,root,qt,parent,q0,q1,q2,bc,scale,rev,f,n,doneptr) |
533 |
int *argptr; |
534 |
int root; |
535 |
QUADTREE qt,parent; |
536 |
BCOORD q0[3],q1[3],q2[3],bc[3]; |
537 |
unsigned int scale,rev; |
538 |
FUNC f; |
539 |
int n,*doneptr; |
540 |
{ |
541 |
S_ID s_id; |
542 |
S_ID *optr; |
543 |
|
544 |
s_id = ((S_ARGS *)argptr)->s_id; |
545 |
/* If the set is empty - just add */ |
546 |
if(QT_IS_EMPTY(qt)) |
547 |
{ |
548 |
qt = qtadduelem(qt,s_id); |
549 |
SM_S_NTH_QT(smMesh,s_id) = qt; |
550 |
if(((S_ARGS *)argptr)->n_id) |
551 |
*doneptr = FALSE; |
552 |
else |
553 |
*doneptr = TRUE; |
554 |
return(qt); |
555 |
} |
556 |
/* If the set size is below expansion threshold,or at maximum |
557 |
number of quadtree levels : just add */ |
558 |
optr = qtqueryset(qt); |
559 |
if(QT_SET_CNT(optr) < QT_SET_THRESHOLD || (n > (QT_MAX_LEVELS-2))) |
560 |
{ |
561 |
qt = qtadduelem(qt,s_id); |
562 |
|
563 |
SM_S_NTH_QT(smMesh,s_id) = qt; |
564 |
if(((S_ARGS *)argptr)->n_id) |
565 |
if(QT_SET_CNT(qtqueryset(qt)) > 1) |
566 |
{ |
567 |
((S_ARGS *)argptr)->n_id = qtqueryset(qt)[1]; |
568 |
*doneptr = TRUE; |
569 |
} |
570 |
else |
571 |
*doneptr = FALSE; |
572 |
else |
573 |
*doneptr = TRUE; |
574 |
return(qt); |
575 |
} |
576 |
/* otherwise: expand node- and insert sample, and reinsert existing samples |
577 |
in set to children of new node |
578 |
*/ |
579 |
{ |
580 |
OBJECT *sptr,s_set[QT_MAXSET+1]; |
581 |
FUNC sfunc; |
582 |
S_ARGS args; |
583 |
FVECT p; |
584 |
BCOORD bp[3]; |
585 |
int i; |
586 |
|
587 |
if(QT_SET_CNT(optr) > QT_MAXSET) |
588 |
{ |
589 |
if(!(sptr = (OBJECT *)malloc((QT_SET_CNT(optr)+1)*sizeof(OBJECT)))) |
590 |
goto memerr; |
591 |
} |
592 |
else |
593 |
sptr = s_set; |
594 |
|
595 |
qtgetset(sptr,qt); |
596 |
|
597 |
/* subdivide node */ |
598 |
qtfreeleaf(qt); |
599 |
qtSubdivide(qt); |
600 |
|
601 |
/* Now add in all of the rest; */ |
602 |
F_FUNC(sfunc) = F_FUNC(f); |
603 |
F_ARGS(sfunc) = (int *) (&args); |
604 |
args.n_id = 0; |
605 |
for(optr = sptr,i=QT_SET_CNT(sptr); i > 0; i--) |
606 |
{ |
607 |
s_id = QT_SET_NEXT_ELEM(optr); |
608 |
args.s_id = s_id; |
609 |
VSUB(p,SM_NTH_WV(smMesh,s_id),SM_VIEW_CENTER(smMesh)); |
610 |
normalize(p); |
611 |
vert_to_qt_frame(i,p,bp); |
612 |
if(rev) |
613 |
qt= qtInsert_point_rev(root,qt,parent,q0,q1,q2,bp, |
614 |
scale,sfunc,n,doneptr); |
615 |
else |
616 |
qt= qtInsert_point(root,qt,parent,q0,q1,q2,bp, |
617 |
scale,sfunc,n,doneptr); |
618 |
} |
619 |
/* Add current sample: have all of the information */ |
620 |
if(rev) |
621 |
qt =qtInsert_point_rev(root,qt,parent,q0,q1,q2,bc,scale,f,n,doneptr); |
622 |
else |
623 |
qt = qtInsert_point(root,qt,parent,q0,q1,q2,bc,scale,f,n,doneptr); |
624 |
|
625 |
/* If we allocated memory: free it */ |
626 |
|
627 |
if( sptr != s_set) |
628 |
free(sptr); |
629 |
|
630 |
return(qt); |
631 |
} |
632 |
memerr: |
633 |
error(SYSTEM,"expand_node():Unable to allocate memory"); |
634 |
|
635 |
} |
636 |
|
637 |
|
638 |
/* |
639 |
* int |
640 |
* smAdd_tri(sm,v0_id,v1_id,v2_id,tptr) |
641 |
* : Add a triangle to the base array with vertices v0-v1-v2, |
642 |
* returns ptr to triangle in tptr |
643 |
* SM *sm; : mesh |
644 |
* S_ID v0_id,v1_id,v2_id; : sample ids of triangle vertices |
645 |
* TRI **tptr; : ptr to set to triangle |
646 |
* |
647 |
* Allocates and initializes mesh triangle with vertices specified. |
648 |
*/ |
649 |
int |
650 |
smAdd_tri(sm, v0_id,v1_id,v2_id,tptr) |
651 |
SM *sm; |
652 |
S_ID v0_id,v1_id,v2_id; |
653 |
TRI **tptr; |
654 |
{ |
655 |
int t_id; |
656 |
TRI *t; |
657 |
|
658 |
#ifdef DEBUG |
659 |
if(v0_id==v1_id || v0_id==v2_id || v1_id==v2_id) |
660 |
error(CONSISTENCY,"smAdd_tri: invalid vertex ids\n"); |
661 |
|
662 |
#endif |
663 |
t_id = smAlloc_tri(sm); |
664 |
#ifdef DEBUG |
665 |
#if DEBUG > 1 |
666 |
{ |
667 |
double v0[3],v1[3],v2[3],n[3]; |
668 |
double area,dp; |
669 |
double ab[3],ac[3]; |
670 |
VSUB(v0,SM_NTH_WV(sm,v0_id),SM_VIEW_CENTER(sm)); |
671 |
VSUB(v1,SM_NTH_WV(sm,v1_id),SM_VIEW_CENTER(sm)); |
672 |
VSUB(v2,SM_NTH_WV(sm,v2_id),SM_VIEW_CENTER(sm)); |
673 |
normalize(v0); |
674 |
normalize(v1); |
675 |
normalize(v2); |
676 |
|
677 |
VSUB(ab,v1,v2); |
678 |
normalize(ab); |
679 |
VSUB(ac,v0,v2); |
680 |
normalize(ac); |
681 |
VCROSS(n,ab,ac); |
682 |
area = normalize(n); |
683 |
if((dp=DOT(v0,n)) < 0.0) |
684 |
{ |
685 |
eputs("backwards tri\n"); |
686 |
} |
687 |
} |
688 |
#endif |
689 |
#endif |
690 |
|
691 |
t = SM_NTH_TRI(sm,t_id); |
692 |
#ifdef DEBUG |
693 |
T_CLEAR_NBRS(t); |
694 |
#endif |
695 |
/* set the triangle vertex ids */ |
696 |
T_NTH_V(t,0) = v0_id; |
697 |
T_NTH_V(t,1) = v1_id; |
698 |
T_NTH_V(t,2) = v2_id; |
699 |
|
700 |
SM_NTH_VERT(sm,v0_id) = t_id; |
701 |
SM_NTH_VERT(sm,v1_id) = t_id; |
702 |
SM_NTH_VERT(sm,v2_id) = t_id; |
703 |
|
704 |
if(SM_BASE_ID(sm,v0_id) || SM_BASE_ID(sm,v1_id) || SM_BASE_ID(sm,v2_id)) |
705 |
SM_SET_NTH_T_BASE(sm,t_id); |
706 |
else |
707 |
SM_CLR_NTH_T_BASE(sm,t_id); |
708 |
if(SM_DIR_ID(sm,v0_id) || SM_DIR_ID(sm,v1_id) || SM_DIR_ID(sm,v2_id)) |
709 |
SM_SET_NTH_T_BG(sm,t_id); |
710 |
else |
711 |
SM_CLR_NTH_T_BG(sm,t_id); |
712 |
S_SET_FLAG(T_NTH_V(t,0)); |
713 |
S_SET_FLAG(T_NTH_V(t,1)); |
714 |
S_SET_FLAG(T_NTH_V(t,2)); |
715 |
|
716 |
SM_SET_NTH_T_ACTIVE(sm,t_id); |
717 |
SM_SET_NTH_T_NEW(sm,t_id); |
718 |
|
719 |
*tptr = t; |
720 |
/* return initialized triangle */ |
721 |
return(t_id); |
722 |
} |
723 |
|
724 |
|
725 |
|
726 |
smRestore_Delaunay(sm,a,b,c,t,t_id,a_id,b_id,c_id) |
727 |
SM *sm; |
728 |
FVECT a,b,c; |
729 |
TRI *t; |
730 |
int t_id,a_id,b_id,c_id; |
731 |
{ |
732 |
int e1,topp_id; |
733 |
S_ID p_id; |
734 |
TRI *topp; |
735 |
FVECT p; |
736 |
|
737 |
topp_id = T_NTH_NBR(t,0); |
738 |
#ifdef DEBUG |
739 |
if(topp_id==INVALID) |
740 |
{ |
741 |
eputs("Invalid tri id smRestore_delaunay()\n"); |
742 |
return; |
743 |
} |
744 |
#endif |
745 |
topp = SM_NTH_TRI(sm,topp_id); |
746 |
#ifdef DEBUG |
747 |
if(!T_IS_VALID(topp)) |
748 |
{ |
749 |
eputs("Invalid tri smRestore_delaunay()\n"); |
750 |
return; |
751 |
} |
752 |
#endif |
753 |
e1 = T_NTH_NBR_PTR(t_id,topp); |
754 |
p_id = T_NTH_V(topp,e1); |
755 |
|
756 |
VSUB(p,SM_NTH_WV(sm,p_id),SM_VIEW_CENTER(sm)); |
757 |
normalize(p); |
758 |
if(pt_in_cone(p,c,b,a)) |
759 |
{ |
760 |
int e1next,e1prev; |
761 |
int ta_id,tb_id; |
762 |
TRI *ta,*tb,*n; |
763 |
e1next = (e1 + 1)%3; |
764 |
e1prev = (e1 + 2)%3; |
765 |
ta_id = smAdd_tri(sm,a_id,b_id,p_id,&ta); |
766 |
tb_id = smAdd_tri(sm,a_id,p_id,c_id,&tb); |
767 |
|
768 |
T_NTH_NBR(ta,0) = T_NTH_NBR(topp,e1next); |
769 |
T_NTH_NBR(ta,1) = tb_id; |
770 |
T_NTH_NBR(ta,2) = T_NTH_NBR(t,2); |
771 |
|
772 |
T_NTH_NBR(tb,0) = T_NTH_NBR(topp,e1prev); |
773 |
T_NTH_NBR(tb,1) = T_NTH_NBR(t,1); |
774 |
T_NTH_NBR(tb,2) = ta_id; |
775 |
|
776 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t,1)); |
777 |
T_NTH_NBR(n,T_NTH_NBR_PTR(t_id,n)) = tb_id; |
778 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t,2)); |
779 |
T_NTH_NBR(n,T_NTH_NBR_PTR(t_id,n)) = ta_id; |
780 |
n = SM_NTH_TRI(sm,T_NTH_NBR(topp,e1next)); |
781 |
T_NTH_NBR(n,T_NTH_NBR_PTR(topp_id,n)) = ta_id; |
782 |
n = SM_NTH_TRI(sm,T_NTH_NBR(topp,e1prev)); |
783 |
T_NTH_NBR(n,T_NTH_NBR_PTR(topp_id,n)) = tb_id; |
784 |
|
785 |
smDelete_tri(sm,t_id,t); |
786 |
smDelete_tri(sm,topp_id,topp); |
787 |
|
788 |
#ifdef DEBUG |
789 |
#if DEBUG > 1 |
790 |
if(T_NTH_NBR(ta,0) == T_NTH_NBR(ta,1) || |
791 |
T_NTH_NBR(ta,1) == T_NTH_NBR(ta,2) || |
792 |
T_NTH_NBR(ta,0) == T_NTH_NBR(ta,2)) |
793 |
error(CONSISTENCY,"Invalid topology\n"); |
794 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(ta,0))) || |
795 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(ta,1))) || |
796 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(ta,2)))) |
797 |
error(CONSISTENCY,"Invalid topology\n"); |
798 |
n = SM_NTH_TRI(sm,T_NTH_NBR(ta,0)); |
799 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
800 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
801 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
802 |
error(CONSISTENCY,"Invalid topology\n"); |
803 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
804 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
805 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
806 |
error(CONSISTENCY,"Invalid topology\n"); |
807 |
n = SM_NTH_TRI(sm,T_NTH_NBR(ta,1)); |
808 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
809 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
810 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
811 |
error(CONSISTENCY,"Invalid topology\n"); |
812 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
813 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
814 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
815 |
error(CONSISTENCY,"Invalid topology\n"); |
816 |
n = SM_NTH_TRI(sm,T_NTH_NBR(ta,2)); |
817 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
818 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
819 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
820 |
error(CONSISTENCY,"Invalid topology\n"); |
821 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
822 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
823 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
824 |
error(CONSISTENCY,"Invalid topology\n"); |
825 |
n = SM_NTH_TRI(sm,T_NTH_NBR(tb,0)); |
826 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
827 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
828 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
829 |
error(CONSISTENCY,"Invalid topology\n"); |
830 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
831 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
832 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
833 |
error(CONSISTENCY,"Invalid topology\n"); |
834 |
n = SM_NTH_TRI(sm,T_NTH_NBR(tb,1)); |
835 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
836 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
837 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
838 |
error(CONSISTENCY,"Invalid topology\n"); |
839 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
840 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
841 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
842 |
error(CONSISTENCY,"Invalid topology\n"); |
843 |
n = SM_NTH_TRI(sm,T_NTH_NBR(tb,2)); |
844 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
845 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
846 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
847 |
error(CONSISTENCY,"Invalid topology\n"); |
848 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
849 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
850 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
851 |
error(CONSISTENCY,"Invalid topology\n"); |
852 |
|
853 |
if(T_NTH_NBR(tb,0) == T_NTH_NBR(tb,1) || |
854 |
T_NTH_NBR(tb,1) == T_NTH_NBR(tb,2) || |
855 |
T_NTH_NBR(tb,0) == T_NTH_NBR(tb,2)) |
856 |
error(CONSISTENCY,"Invalid topology\n"); |
857 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(tb,0))) || |
858 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(tb,1))) || |
859 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(tb,2)))) |
860 |
error(CONSISTENCY,"Invalid topology\n"); |
861 |
|
862 |
#endif |
863 |
#endif |
864 |
smRestore_Delaunay(sm,a,b,p,ta,ta_id,a_id,b_id,p_id); |
865 |
smRestore_Delaunay(sm,a,p,c,tb,tb_id,a_id,p_id,c_id); |
866 |
} |
867 |
} |
868 |
|
869 |
|
870 |
/* Give the vertex "id" and a triangle "t" that it belongs to- return the |
871 |
next nbr in a counter clockwise order about vertex "id" |
872 |
*/ |
873 |
int |
874 |
smTri_next_ccw_nbr(sm,t,id) |
875 |
SM *sm; |
876 |
TRI *t; |
877 |
S_ID id; |
878 |
{ |
879 |
int which; |
880 |
int nbr_id; |
881 |
|
882 |
/* Want the edge for which "id" is the destination */ |
883 |
which = T_WHICH_V(t,id); |
884 |
if(which== INVALID) |
885 |
return(which); |
886 |
|
887 |
nbr_id = T_NTH_NBR(t,(which + 1)% 3); |
888 |
return(nbr_id); |
889 |
} |
890 |
|
891 |
smClear_tri_flags(sm,id) |
892 |
SM *sm; |
893 |
int id; |
894 |
{ |
895 |
int i; |
896 |
|
897 |
for(i=0; i < T_FLAGS; i++) |
898 |
SM_CLR_NTH_T_FLAG(sm,id,i); |
899 |
|
900 |
} |
901 |
|
902 |
/* Locate the point-id in the point location structure: */ |
903 |
int |
904 |
smInsert_samp_mesh(sm,s_id,tri_id,a,b,c,d,on,which) |
905 |
SM *sm; |
906 |
S_ID s_id; |
907 |
int tri_id; |
908 |
FVECT a,b,c,d; |
909 |
int on,which; |
910 |
{ |
911 |
S_ID v_id[3],opp_id; |
912 |
int topp_id,i; |
913 |
int t0_id,t1_id,t2_id,t3_id; |
914 |
int e0,e1,e2,opp0,opp1,opp2; |
915 |
TRI *tri,*nbr,*topp,*t0,*t1,*t2,*t3; |
916 |
FVECT e; |
917 |
|
918 |
for(i=0; i<3;i++) |
919 |
v_id[i] = T_NTH_V(SM_NTH_TRI(sm,tri_id),i); |
920 |
|
921 |
/* If falls on existing edge */ |
922 |
if(on == ON_E) |
923 |
{ |
924 |
FVECT n,vopp; |
925 |
double dp; |
926 |
|
927 |
tri = SM_NTH_TRI(sm,tri_id); |
928 |
topp_id = T_NTH_NBR(tri,which); |
929 |
e0 = which; |
930 |
e1 = (which+1)%3; |
931 |
e2 = (which+2)%3; |
932 |
topp = SM_NTH_TRI(sm,topp_id); |
933 |
opp0 = T_NTH_NBR_PTR(tri_id,topp); |
934 |
opp1 = (opp0+1)%3; |
935 |
opp2 = (opp0+2)%3; |
936 |
|
937 |
opp_id = T_NTH_V(topp,opp0); |
938 |
|
939 |
/* Create 4 triangles */ |
940 |
/* /|\ /|\ |
941 |
/ | \ / | \ |
942 |
/ * \ ----> /__|__\ |
943 |
\ | / \ | / |
944 |
\ | / \ | / |
945 |
\|/ \|/ |
946 |
*/ |
947 |
t0_id = smAdd_tri(sm,s_id,v_id[e0],v_id[e1],&t0); |
948 |
t1_id = smAdd_tri(sm,s_id,v_id[e2],v_id[e0],&t1); |
949 |
t2_id = smAdd_tri(sm,s_id,v_id[e1],opp_id,&t2); |
950 |
t3_id = smAdd_tri(sm,s_id,opp_id,v_id[e2],&t3); |
951 |
|
952 |
/* Set the neighbor pointers for the new tris */ |
953 |
T_NTH_NBR(t0,0) = T_NTH_NBR(tri,e2); |
954 |
T_NTH_NBR(t0,1) = t2_id; |
955 |
T_NTH_NBR(t0,2) = t1_id; |
956 |
T_NTH_NBR(t1,0) = T_NTH_NBR(tri,e1); |
957 |
T_NTH_NBR(t1,1) = t0_id; |
958 |
T_NTH_NBR(t1,2) = t3_id; |
959 |
T_NTH_NBR(t2,0) = T_NTH_NBR(topp,opp1); |
960 |
T_NTH_NBR(t2,1) = t3_id; |
961 |
T_NTH_NBR(t2,2) = t0_id; |
962 |
T_NTH_NBR(t3,0) = T_NTH_NBR(topp,opp2); |
963 |
T_NTH_NBR(t3,1) = t1_id; |
964 |
T_NTH_NBR(t3,2) = t2_id; |
965 |
|
966 |
/* Reset the neigbor pointers for the neighbors of the original */ |
967 |
nbr = SM_NTH_TRI(sm,T_NTH_NBR(tri,e1)); |
968 |
T_NTH_NBR(nbr,T_NTH_NBR_PTR(tri_id,nbr)) = t1_id; |
969 |
nbr = SM_NTH_TRI(sm,T_NTH_NBR(tri,e2)); |
970 |
T_NTH_NBR(nbr,T_NTH_NBR_PTR(tri_id,nbr)) = t0_id; |
971 |
nbr = SM_NTH_TRI(sm,T_NTH_NBR(topp,opp1)); |
972 |
T_NTH_NBR(nbr,T_NTH_NBR_PTR(topp_id,nbr)) = t2_id; |
973 |
nbr = SM_NTH_TRI(sm,T_NTH_NBR(topp,opp2)); |
974 |
T_NTH_NBR(nbr,T_NTH_NBR_PTR(topp_id,nbr)) = t3_id; |
975 |
|
976 |
#ifdef DEBUG |
977 |
#if DEBUG > 1 |
978 |
{ |
979 |
TRI *n; |
980 |
|
981 |
if(T_NTH_NBR(t0,0) == T_NTH_NBR(t0,1) || |
982 |
T_NTH_NBR(t0,1) == T_NTH_NBR(t0,2) || |
983 |
T_NTH_NBR(t0,0) == T_NTH_NBR(t0,2)) |
984 |
error(CONSISTENCY,"Invalid topology\n"); |
985 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t0,0))) || |
986 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t0,1))) || |
987 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t0,2)))) |
988 |
error(CONSISTENCY,"Invalid topology\n"); |
989 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t0,0)); |
990 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
991 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
992 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
993 |
error(CONSISTENCY,"Invalid topology\n"); |
994 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
995 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
996 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
997 |
error(CONSISTENCY,"Invalid topology\n"); |
998 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t0,1)); |
999 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1000 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1001 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1002 |
error(CONSISTENCY,"Invalid topology\n"); |
1003 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1004 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1005 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1006 |
error(CONSISTENCY,"Invalid topology\n"); |
1007 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t0,2)); |
1008 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1009 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1010 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1011 |
error(CONSISTENCY,"Invalid topology\n"); |
1012 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1013 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1014 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1015 |
error(CONSISTENCY,"Invalid topology\n"); |
1016 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t1,0)); |
1017 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1018 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1019 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1020 |
error(CONSISTENCY,"Invalid topology\n"); |
1021 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1022 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1023 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1024 |
error(CONSISTENCY,"Invalid topology\n"); |
1025 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t1,1)); |
1026 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1027 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1028 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1029 |
error(CONSISTENCY,"Invalid topology\n"); |
1030 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1031 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1032 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1033 |
error(CONSISTENCY,"Invalid topology\n"); |
1034 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t1,2)); |
1035 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1036 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1037 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1038 |
error(CONSISTENCY,"Invalid topology\n"); |
1039 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1040 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1041 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1042 |
error(CONSISTENCY,"Invalid topology\n"); |
1043 |
|
1044 |
if(T_NTH_NBR(t1,0) == T_NTH_NBR(t1,1) || |
1045 |
T_NTH_NBR(t1,1) == T_NTH_NBR(t1,2) || |
1046 |
T_NTH_NBR(t1,0) == T_NTH_NBR(t1,2)) |
1047 |
error(CONSISTENCY,"Invalid topology\n"); |
1048 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t1,0))) || |
1049 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t1,1))) || |
1050 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t1,2)))) |
1051 |
error(CONSISTENCY,"Invalid topology\n"); |
1052 |
|
1053 |
if(T_NTH_NBR(t2,0) == T_NTH_NBR(t2,1) || |
1054 |
T_NTH_NBR(t2,1) == T_NTH_NBR(t2,2) || |
1055 |
T_NTH_NBR(t2,0) == T_NTH_NBR(t2,2)) |
1056 |
error(CONSISTENCY,"Invalid topology\n"); |
1057 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t2,0))) || |
1058 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t2,1))) || |
1059 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t2,2)))) |
1060 |
error(CONSISTENCY,"Invalid topology\n"); |
1061 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t2,0)); |
1062 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1063 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1064 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1065 |
error(CONSISTENCY,"Invalid topology\n"); |
1066 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1067 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1068 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1069 |
error(CONSISTENCY,"Invalid topology\n"); |
1070 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t2,1)); |
1071 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1072 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1073 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1074 |
error(CONSISTENCY,"Invalid topology\n"); |
1075 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1076 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1077 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1078 |
error(CONSISTENCY,"Invalid topology\n"); |
1079 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t2,2)); |
1080 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1081 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1082 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1083 |
error(CONSISTENCY,"Invalid topology\n"); |
1084 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1085 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1086 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1087 |
error(CONSISTENCY,"Invalid topology\n"); |
1088 |
|
1089 |
if(T_NTH_NBR(t3,0) == T_NTH_NBR(t3,1) || |
1090 |
T_NTH_NBR(t3,1) == T_NTH_NBR(t3,2) || |
1091 |
T_NTH_NBR(t3,0) == T_NTH_NBR(t3,2)) |
1092 |
error(CONSISTENCY,"Invalid topology\n"); |
1093 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t3,0))) || |
1094 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t3,1))) || |
1095 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t3,2)))) |
1096 |
error(CONSISTENCY,"Invalid topology\n"); |
1097 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t3,0)); |
1098 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1099 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1100 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1101 |
error(CONSISTENCY,"Invalid topology\n"); |
1102 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1103 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1104 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1105 |
error(CONSISTENCY,"Invalid topology\n"); |
1106 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t3,1)); |
1107 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1108 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1109 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1110 |
error(CONSISTENCY,"Invalid topology\n"); |
1111 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1112 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1113 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1114 |
error(CONSISTENCY,"Invalid topology\n"); |
1115 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t3,2)); |
1116 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1117 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1118 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1119 |
error(CONSISTENCY,"Invalid topology\n"); |
1120 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1121 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1122 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1123 |
error(CONSISTENCY,"Invalid topology\n"); |
1124 |
} |
1125 |
#endif |
1126 |
#endif |
1127 |
smDir(sm,e,opp_id); |
1128 |
if(which == 0) |
1129 |
{ |
1130 |
smRestore_Delaunay(sm,a,b,c,t0,t0_id,s_id,v_id[e0],v_id[e1]); |
1131 |
smRestore_Delaunay(sm,a,d,b,t1,t1_id,s_id,v_id[e2],v_id[e0]); |
1132 |
smRestore_Delaunay(sm,a,c,e,t2,t2_id,s_id,v_id[e1],opp_id); |
1133 |
smRestore_Delaunay(sm,a,e,d,t3,t3_id,s_id,opp_id,v_id[e2]); |
1134 |
} |
1135 |
else |
1136 |
if( which==1 ) |
1137 |
{ |
1138 |
smRestore_Delaunay(sm,a,c,d,t0,t0_id,s_id,v_id[e0],v_id[e1]); |
1139 |
smRestore_Delaunay(sm,a,b,c,t1,t1_id,s_id,v_id[e2],v_id[e0]); |
1140 |
smRestore_Delaunay(sm,a,d,e,t2,t2_id,s_id,v_id[e1],opp_id); |
1141 |
smRestore_Delaunay(sm,a,e,b,t3,t3_id,s_id,opp_id,v_id[e2]); |
1142 |
} |
1143 |
else |
1144 |
{ |
1145 |
smRestore_Delaunay(sm,a,d,b,t0,t0_id,s_id,v_id[e0],v_id[e1]); |
1146 |
smRestore_Delaunay(sm,a,c,d,t1,t1_id,s_id,v_id[e2],v_id[e0]); |
1147 |
smRestore_Delaunay(sm,a,b,e,t2,t2_id,s_id,v_id[e1],opp_id); |
1148 |
smRestore_Delaunay(sm,a,e,c,t3,t3_id,s_id,opp_id,v_id[e2]); |
1149 |
} |
1150 |
smDelete_tri(sm,tri_id,tri); |
1151 |
smDelete_tri(sm,topp_id,topp); |
1152 |
return(TRUE); |
1153 |
} |
1154 |
Linsert_in_tri: |
1155 |
/* Create 3 triangles */ |
1156 |
/* / \ /|\ |
1157 |
/ \ / | \ |
1158 |
/ * \ ----> / | \ |
1159 |
/ \ / / \ \ |
1160 |
/ \ / / \ \ |
1161 |
___________\ //_________\\ |
1162 |
*/ |
1163 |
tri = SM_NTH_TRI(sm,tri_id); |
1164 |
|
1165 |
t0_id = smAdd_tri(sm,s_id,v_id[0],v_id[1],&t0); |
1166 |
t1_id = smAdd_tri(sm,s_id,v_id[1],v_id[2],&t1); |
1167 |
t2_id = smAdd_tri(sm,s_id,v_id[2],v_id[0],&t2); |
1168 |
|
1169 |
/* Set the neighbor pointers for the new tris */ |
1170 |
T_NTH_NBR(t0,0) = T_NTH_NBR(tri,2); |
1171 |
T_NTH_NBR(t0,1) = t1_id; |
1172 |
T_NTH_NBR(t0,2) = t2_id; |
1173 |
T_NTH_NBR(t1,0) = T_NTH_NBR(tri,0); |
1174 |
T_NTH_NBR(t1,1) = t2_id; |
1175 |
T_NTH_NBR(t1,2) = t0_id; |
1176 |
T_NTH_NBR(t2,0) = T_NTH_NBR(tri,1); |
1177 |
T_NTH_NBR(t2,1) = t0_id; |
1178 |
T_NTH_NBR(t2,2) = t1_id; |
1179 |
|
1180 |
/* Reset the neigbor pointers for the neighbors of the original */ |
1181 |
nbr = SM_NTH_TRI(sm,T_NTH_NBR(tri,0)); |
1182 |
T_NTH_NBR(nbr,T_NTH_NBR_PTR(tri_id,nbr)) = t1_id; |
1183 |
nbr = SM_NTH_TRI(sm,T_NTH_NBR(tri,1)); |
1184 |
T_NTH_NBR(nbr,T_NTH_NBR_PTR(tri_id,nbr)) = t2_id; |
1185 |
nbr = SM_NTH_TRI(sm,T_NTH_NBR(tri,2)); |
1186 |
T_NTH_NBR(nbr,T_NTH_NBR_PTR(tri_id,nbr)) = t0_id; |
1187 |
#ifdef DEBUG |
1188 |
#if DEBUG > 1 |
1189 |
{ |
1190 |
TRI *n; |
1191 |
if(T_NTH_NBR(t0,0) == T_NTH_NBR(t0,1) || |
1192 |
T_NTH_NBR(t0,1) == T_NTH_NBR(t0,2) || |
1193 |
T_NTH_NBR(t0,0) == T_NTH_NBR(t0,2)) |
1194 |
error(CONSISTENCY,"Invalid topology\n"); |
1195 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t0,0))) || |
1196 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t0,1))) || |
1197 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t0,2)))) |
1198 |
error(CONSISTENCY,"Invalid topology\n"); |
1199 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t0,0)); |
1200 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1201 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1202 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1203 |
error(CONSISTENCY,"Invalid topology\n"); |
1204 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1205 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1206 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1207 |
error(CONSISTENCY,"Invalid topology\n"); |
1208 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t0,1)); |
1209 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1210 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1211 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1212 |
error(CONSISTENCY,"Invalid topology\n"); |
1213 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1214 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1215 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1216 |
error(CONSISTENCY,"Invalid topology\n"); |
1217 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t0,2)); |
1218 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1219 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1220 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1221 |
error(CONSISTENCY,"Invalid topology\n"); |
1222 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1223 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1224 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1225 |
error(CONSISTENCY,"Invalid topology\n"); |
1226 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t1,0)); |
1227 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1228 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1229 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1230 |
error(CONSISTENCY,"Invalid topology\n"); |
1231 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1232 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1233 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1234 |
error(CONSISTENCY,"Invalid topology\n"); |
1235 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t1,1)); |
1236 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1237 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1238 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1239 |
error(CONSISTENCY,"Invalid topology\n"); |
1240 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1241 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1242 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1243 |
error(CONSISTENCY,"Invalid topology\n"); |
1244 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t1,2)); |
1245 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1246 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1247 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1248 |
error(CONSISTENCY,"Invalid topology\n"); |
1249 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1250 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1251 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1252 |
error(CONSISTENCY,"Invalid topology\n"); |
1253 |
|
1254 |
if(T_NTH_NBR(t1,0) == T_NTH_NBR(t1,1) || |
1255 |
T_NTH_NBR(t1,1) == T_NTH_NBR(t1,2) || |
1256 |
T_NTH_NBR(t1,0) == T_NTH_NBR(t1,2)) |
1257 |
error(CONSISTENCY,"Invalid topology\n"); |
1258 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t1,0))) || |
1259 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t1,1))) || |
1260 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t1,2)))) |
1261 |
error(CONSISTENCY,"Invalid topology\n"); |
1262 |
|
1263 |
if(T_NTH_NBR(t2,0) == T_NTH_NBR(t2,1) || |
1264 |
T_NTH_NBR(t2,1) == T_NTH_NBR(t2,2) || |
1265 |
T_NTH_NBR(t2,0) == T_NTH_NBR(t2,2)) |
1266 |
error(CONSISTENCY,"Invalid topology\n"); |
1267 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t2,0))) || |
1268 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t2,1))) || |
1269 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(t2,2)))) |
1270 |
error(CONSISTENCY,"Invalid topology\n"); |
1271 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t2,0)); |
1272 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1273 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1274 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1275 |
error(CONSISTENCY,"Invalid topology\n"); |
1276 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1277 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1278 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1279 |
error(CONSISTENCY,"Invalid topology\n"); |
1280 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t2,1)); |
1281 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1282 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1283 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1284 |
error(CONSISTENCY,"Invalid topology\n"); |
1285 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1286 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1287 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1288 |
error(CONSISTENCY,"Invalid topology\n"); |
1289 |
n = SM_NTH_TRI(sm,T_NTH_NBR(t2,2)); |
1290 |
if(T_NTH_NBR(n,0) == T_NTH_NBR(n,1) || |
1291 |
T_NTH_NBR(n,1) == T_NTH_NBR(n,2) || |
1292 |
T_NTH_NBR(n,0) == T_NTH_NBR(n,2)) |
1293 |
error(CONSISTENCY,"Invalid topology\n"); |
1294 |
if(!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,0))) || |
1295 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,1))) || |
1296 |
!T_IS_VALID(SM_NTH_TRI(sm,T_NTH_NBR(n,2)))) |
1297 |
error(CONSISTENCY,"Invalid topology\n"); |
1298 |
} |
1299 |
#endif |
1300 |
#endif |
1301 |
smRestore_Delaunay(sm,a,b,c,t0,t0_id,s_id,v_id[0],v_id[1]); |
1302 |
smRestore_Delaunay(sm,a,c,d,t1,t1_id,s_id,v_id[1],v_id[2]); |
1303 |
smRestore_Delaunay(sm,a,d,b,t2,t2_id,s_id,v_id[2],v_id[0]); |
1304 |
smDelete_tri(sm,tri_id,tri); |
1305 |
return(TRUE); |
1306 |
|
1307 |
#ifdef DEBUG |
1308 |
Ladderror: |
1309 |
error(CONSISTENCY,"Invalid tri: smInsert_samp_mesh()\n"); |
1310 |
#endif |
1311 |
} |
1312 |
|
1313 |
|
1314 |
int |
1315 |
smWalk(sm,p,t_id,t,onptr,wptr,from,on_edge,a,b) |
1316 |
SM *sm; |
1317 |
FVECT p; |
1318 |
int t_id; |
1319 |
TRI *t; |
1320 |
int *onptr,*wptr; |
1321 |
int from; |
1322 |
double on_edge; |
1323 |
FVECT a,b; |
1324 |
{ |
1325 |
FVECT n,v0,v1,v2; |
1326 |
TRI *tn; |
1327 |
double on0,on1,on2; |
1328 |
int tn_id; |
1329 |
|
1330 |
#ifdef DEBUG |
1331 |
Wcnt++; |
1332 |
on0 = on1 = on2 = 10; |
1333 |
#endif |
1334 |
switch(from){ |
1335 |
case 0: |
1336 |
on0 = on_edge; |
1337 |
/* Havnt calculate v0 yet: check for equality first */ |
1338 |
VSUB(v0,SM_T_NTH_WV(sm,t,0),SM_VIEW_CENTER(sm)); |
1339 |
normalize(v0); |
1340 |
if(EQUAL_VEC3(v0,p)){ *onptr = ON_V; *wptr = 0; return(t_id); } |
1341 |
/* determine what side of edge v0v1 (v0a) point is on*/ |
1342 |
VCROSS(n,v0,a); |
1343 |
normalize(n); |
1344 |
on2 = DOT(n,p); |
1345 |
if(on2 > 0.0) |
1346 |
{ |
1347 |
tn_id = T_NTH_NBR(t,2); |
1348 |
tn = SM_NTH_TRI(sm,tn_id); |
1349 |
return(smWalk(sm,p,tn_id,tn,onptr,wptr,T_NTH_NBR_PTR(t_id,tn), |
1350 |
-on2,a,v0)); |
1351 |
} |
1352 |
else |
1353 |
if(on2 >= -EDGE_EPS) |
1354 |
{ |
1355 |
if(on0 >= -EDGE_EPS) |
1356 |
{ |
1357 |
/* Could either be epsilon of vertex 1*/ |
1358 |
/* dot(p,a) == cos angle between them. Want length of chord x to |
1359 |
be <= EDGE_EPS for test. if the perpendicular bisector of pa |
1360 |
is d, cos@/2 = d/1, with right triangle d^2 + (x/2)^2 = 1 |
1361 |
or x^2 = 4(1-cos^2@/2) = 4(1- (1 + cos@)/2) = 2 -2cos@, |
1362 |
so test is if x^2 <= VERT_EPS*VERT_EPS, |
1363 |
2 - 2cos@ <= VERT_EPS*VERT_EPS, or... */ |
1364 |
if(DOT(p,a) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1365 |
{*onptr = ON_P; *wptr = 1;} |
1366 |
else |
1367 |
if(on2 > on0) |
1368 |
{*onptr = ON_E; *wptr = 2;} |
1369 |
else |
1370 |
{*onptr = ON_E; *wptr = 0;} |
1371 |
return(t_id); |
1372 |
} |
1373 |
} |
1374 |
|
1375 |
VCROSS(n,b,v0); |
1376 |
normalize(n); |
1377 |
on1 = DOT(n,p); |
1378 |
if(on1 > 0.0) |
1379 |
{ |
1380 |
tn_id = T_NTH_NBR(t,1); |
1381 |
tn = SM_NTH_TRI(sm,tn_id); |
1382 |
return(smWalk(sm,p,tn_id,tn,onptr,wptr,T_NTH_NBR_PTR(t_id,tn), |
1383 |
-on1,v0,b)); |
1384 |
} |
1385 |
else |
1386 |
if(on1 >= -EDGE_EPS) |
1387 |
{ /* Either on v0 or on edge 1 */ |
1388 |
if(on0 >= -EDGE_EPS) |
1389 |
{ |
1390 |
if(DOT(p,b) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1391 |
{*onptr = ON_P; *wptr = 2;} |
1392 |
else |
1393 |
if(on1 > on0) |
1394 |
{*onptr = ON_E; *wptr = 1;} |
1395 |
else |
1396 |
{*onptr = ON_E; *wptr = 0;} |
1397 |
return(t_id); |
1398 |
} |
1399 |
if(on2 >= -EDGE_EPS) |
1400 |
{ |
1401 |
if(DOT(p,v0) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1402 |
{*onptr = ON_P; *wptr = 0;} |
1403 |
else |
1404 |
if( on1 > on2) |
1405 |
{*onptr = ON_E; *wptr = 1;} |
1406 |
else |
1407 |
{*onptr = ON_E; *wptr = 2;} |
1408 |
return(t_id); |
1409 |
} |
1410 |
*onptr = ON_E; *wptr = 1; |
1411 |
return(t_id); |
1412 |
} |
1413 |
else |
1414 |
if(on2 >= -EDGE_EPS) |
1415 |
{ |
1416 |
*onptr = ON_E; *wptr = 2; |
1417 |
return(t_id); |
1418 |
} |
1419 |
if(on0 >= -EDGE_EPS) |
1420 |
{ |
1421 |
*onptr = ON_E; *wptr = 0; |
1422 |
return(t_id); |
1423 |
} |
1424 |
*onptr = IN_T; |
1425 |
return(t_id); |
1426 |
case 1: |
1427 |
on1 = on_edge; |
1428 |
/* Havnt calculate v1 yet: check for equality first */ |
1429 |
VSUB(v1,SM_T_NTH_WV(sm,t,1),SM_VIEW_CENTER(sm)); |
1430 |
normalize(v1); |
1431 |
if(EQUAL_VEC3(v1,p)){ *onptr = ON_V; *wptr = 1; return(t_id); } |
1432 |
/* determine what side of edge v0v1 (v0a) point is on*/ |
1433 |
VCROSS(n,b,v1); |
1434 |
normalize(n); |
1435 |
on2 = DOT(n,p); |
1436 |
if(on2 > 0.0) |
1437 |
{ |
1438 |
tn_id = T_NTH_NBR(t,2); |
1439 |
tn = SM_NTH_TRI(sm,tn_id); |
1440 |
return(smWalk(sm,p,tn_id,tn,onptr,wptr,T_NTH_NBR_PTR(t_id,tn), |
1441 |
-on2,v1,b)); |
1442 |
} |
1443 |
if(on2 >= -EDGE_EPS) |
1444 |
{ |
1445 |
if(on1 >= -EDGE_EPS) |
1446 |
{ |
1447 |
if(DOT(p,b) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1448 |
{ *onptr = ON_P; *wptr = 0;} |
1449 |
else |
1450 |
if(on2 > on1) |
1451 |
{ *onptr = ON_E; *wptr = 2;} |
1452 |
else |
1453 |
{ *onptr = ON_E; *wptr = 1;} |
1454 |
return(t_id); |
1455 |
} |
1456 |
} |
1457 |
|
1458 |
VCROSS(n,v1,a); |
1459 |
normalize(n); |
1460 |
on0 = DOT(n,p); |
1461 |
if(on0 >0.0) |
1462 |
{ |
1463 |
tn_id = T_NTH_NBR(t,0); |
1464 |
tn = SM_NTH_TRI(sm,tn_id); |
1465 |
return(smWalk(sm,p,tn_id,tn,onptr,wptr,T_NTH_NBR_PTR(t_id,tn), |
1466 |
-on0,a,v1)); |
1467 |
} |
1468 |
else |
1469 |
if(on0 >= -EDGE_EPS) |
1470 |
{ /* Either on v0 or on edge 1 */ |
1471 |
if(on1 >= -EDGE_EPS) |
1472 |
{ |
1473 |
if(DOT(p,a) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1474 |
{*onptr = ON_P; *wptr = 2;} |
1475 |
else |
1476 |
if(on0 > on1) |
1477 |
{ *onptr = ON_E; *wptr = 0;} |
1478 |
else |
1479 |
{ *onptr = ON_E; *wptr = 1;} |
1480 |
return(t_id); |
1481 |
} |
1482 |
if(on2 >= -EDGE_EPS) |
1483 |
{ |
1484 |
if(DOT(p,v1) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1485 |
{*onptr = ON_P; *wptr = 1;} |
1486 |
else |
1487 |
if(on0 > on2) |
1488 |
{ *onptr = ON_E; *wptr = 0;} |
1489 |
else |
1490 |
{ *onptr = ON_E; *wptr = 2;} |
1491 |
return(t_id); |
1492 |
} |
1493 |
*onptr = ON_E; *wptr = 0; |
1494 |
return(t_id); |
1495 |
} |
1496 |
else |
1497 |
if(on2 >= -EDGE_EPS) |
1498 |
{ |
1499 |
*onptr = ON_E; *wptr = 2; |
1500 |
return(t_id); |
1501 |
} |
1502 |
if(on1 >= -EDGE_EPS) |
1503 |
{ |
1504 |
*onptr = ON_E; *wptr = 1; |
1505 |
return(t_id); |
1506 |
} |
1507 |
*onptr = IN_T; |
1508 |
return(t_id); |
1509 |
case 2: |
1510 |
on2 = on_edge; |
1511 |
VSUB(v2,SM_T_NTH_WV(sm,t,2),SM_VIEW_CENTER(sm)); |
1512 |
normalize(v2); |
1513 |
if(EQUAL_VEC3(v2,p)){ *onptr = ON_V; *wptr = 2; return(t_id); } |
1514 |
|
1515 |
/* determine what side of edge v0v1 (v0a) point is on*/ |
1516 |
VCROSS(n,b,v2); |
1517 |
normalize(n); |
1518 |
on0 = DOT(n,p); |
1519 |
if(on0 > 0.0) |
1520 |
{ |
1521 |
tn_id = T_NTH_NBR(t,0); |
1522 |
tn = SM_NTH_TRI(sm,tn_id); |
1523 |
return(smWalk(sm,p,tn_id,tn,onptr,wptr,T_NTH_NBR_PTR(t_id,tn), |
1524 |
-on0,v2,b)); |
1525 |
} |
1526 |
else |
1527 |
if(on0 >= -EDGE_EPS) |
1528 |
{ |
1529 |
if(on2 >= - EDGE_EPS) |
1530 |
{ |
1531 |
if(DOT(p,b) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1532 |
{*onptr = ON_P; *wptr = 1;} |
1533 |
else |
1534 |
if(on0 > on2) |
1535 |
{*onptr = ON_E; *wptr = 0;} |
1536 |
else |
1537 |
{*onptr = ON_E; *wptr = 2;} |
1538 |
return(t_id); |
1539 |
} |
1540 |
} |
1541 |
VCROSS(n,v2,a); |
1542 |
normalize(n); |
1543 |
on1 = DOT(n,p); |
1544 |
if(on1 >0.0) |
1545 |
{ |
1546 |
tn_id = T_NTH_NBR(t,1); |
1547 |
tn = SM_NTH_TRI(sm,tn_id); |
1548 |
return(smWalk(sm,p,tn_id,tn,onptr,wptr,T_NTH_NBR_PTR(t_id,tn), |
1549 |
-on1,a,v2)); |
1550 |
} |
1551 |
else |
1552 |
if(on1 >= -EDGE_EPS) |
1553 |
{ /* Either on v0 or on edge 1 */ |
1554 |
if(on0 >= - EDGE_EPS) |
1555 |
{ |
1556 |
if(DOT(p,v2) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1557 |
{*onptr = ON_P;*wptr = 2;} |
1558 |
else |
1559 |
if(on1 > on0) |
1560 |
{*onptr = ON_E;*wptr = 1;} |
1561 |
else |
1562 |
{*onptr = ON_E;*wptr = 0;} |
1563 |
return(t_id); |
1564 |
} |
1565 |
if(on2 >= -EDGE_EPS) |
1566 |
{ |
1567 |
if(DOT(p,a) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1568 |
{*onptr = ON_P;*wptr = 0;} |
1569 |
else |
1570 |
if(on1 > on2) |
1571 |
{*onptr = ON_E;*wptr = 1;} |
1572 |
else |
1573 |
{*onptr = ON_E;*wptr = 2;} |
1574 |
return(t_id); |
1575 |
} |
1576 |
*onptr = ON_E;*wptr = 1; |
1577 |
return(t_id); |
1578 |
} |
1579 |
else |
1580 |
if(on0 >= -EDGE_EPS) |
1581 |
{ |
1582 |
*onptr = ON_E;*wptr = 0; |
1583 |
return(t_id); |
1584 |
} |
1585 |
if(on2 >= -EDGE_EPS) |
1586 |
{ |
1587 |
*onptr = ON_E;*wptr = 2; |
1588 |
return(t_id); |
1589 |
} |
1590 |
*onptr = IN_T; |
1591 |
return(t_id); |
1592 |
default: |
1593 |
/* First time called: havnt tested anything */ |
1594 |
/* Check against vertices */ |
1595 |
VSUB(v0,SM_T_NTH_WV(sm,t,0),SM_VIEW_CENTER(sm)); |
1596 |
normalize(v0); |
1597 |
if(EQUAL_VEC3(v0,p)){ *onptr = ON_V; *wptr = 0; return(t_id); } |
1598 |
VSUB(v1,SM_T_NTH_WV(sm,t,1),SM_VIEW_CENTER(sm)); |
1599 |
normalize(v1); |
1600 |
if(EQUAL_VEC3(v1,p)){ *onptr = ON_V; *wptr = 1; return(t_id); } |
1601 |
VSUB(v2,SM_T_NTH_WV(sm,t,2),SM_VIEW_CENTER(sm)); |
1602 |
normalize(v2); |
1603 |
if(EQUAL_VEC3(v2,p)){ *onptr = ON_V; *wptr = 2; return(t_id); } |
1604 |
|
1605 |
VCROSS(n,v0,v1); /* Check against v0v1, or edge 2 */ |
1606 |
normalize(n); |
1607 |
on2 = DOT(n,p); |
1608 |
if(on2 > 0.0) |
1609 |
{ /* Outside edge: traverse to nbr 2 */ |
1610 |
tn_id = T_NTH_NBR(t,2); |
1611 |
tn = SM_NTH_TRI(sm,tn_id); |
1612 |
return(smWalk(sm,p,tn_id,tn,onptr,wptr,T_NTH_NBR_PTR(t_id,tn), |
1613 |
-on2,v1,v0)); |
1614 |
} |
1615 |
else |
1616 |
VCROSS(n,v1,v2); /* Check against v1v2 or edge 0 */ |
1617 |
normalize(n); |
1618 |
on0 = DOT(n,p); |
1619 |
if(on0 > 0.0) |
1620 |
{ /* Outside edge: traverse to nbr 0 */ |
1621 |
tn_id = T_NTH_NBR(t,0); |
1622 |
tn = SM_NTH_TRI(sm,tn_id); |
1623 |
return(smWalk(sm,p,tn_id,tn,onptr,wptr,T_NTH_NBR_PTR(t_id,tn), |
1624 |
-on0,v2,v1)); |
1625 |
} |
1626 |
else |
1627 |
if(on0 >= -EDGE_EPS) |
1628 |
{ /* On the line defining edge 0 */ |
1629 |
if(on2 >= -EDGE_EPS) |
1630 |
{ |
1631 |
if(DOT(p,v1) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1632 |
{*onptr = ON_P;*wptr = 1;} |
1633 |
else |
1634 |
if(on0 > on2) |
1635 |
{*onptr = ON_E;*wptr = 0;} |
1636 |
else |
1637 |
{*onptr = ON_E;*wptr = 2;} |
1638 |
return(t_id); |
1639 |
} |
1640 |
} |
1641 |
VCROSS(n,v2,v0); /* Check against v2v0 or edge 1 */ |
1642 |
normalize(n); |
1643 |
on1 = DOT(n,p); |
1644 |
if(on1 >0.0) |
1645 |
{ /* Outside edge: traverse to nbr 1 */ |
1646 |
tn_id = T_NTH_NBR(t,1); |
1647 |
tn = SM_NTH_TRI(sm,tn_id); |
1648 |
return(smWalk(sm,p,tn_id,tn,onptr,wptr,T_NTH_NBR_PTR(t_id,tn), |
1649 |
-on1,v0,v2)); |
1650 |
} |
1651 |
else |
1652 |
if(on1 >= -EDGE_EPS) |
1653 |
{ /* On the line defining edge 1 */ |
1654 |
if(on2 >= -EDGE_EPS) |
1655 |
{ |
1656 |
if(DOT(p,v0) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1657 |
{*onptr = ON_P;*wptr = 0;} |
1658 |
else |
1659 |
if(on1 > on2) |
1660 |
{*onptr = ON_E;*wptr = 1;} |
1661 |
else |
1662 |
{*onptr = ON_E;*wptr = 2;} |
1663 |
return(t_id); |
1664 |
} |
1665 |
if(on0 >= -EDGE_EPS) |
1666 |
{ |
1667 |
if(DOT(p,v2) >= 1.0-VERT_EPS*VERT_EPS/2.0) |
1668 |
{*onptr = ON_P;*wptr = 2;} |
1669 |
else |
1670 |
if(on1 > on0) |
1671 |
{*onptr = ON_E;*wptr = 1;} |
1672 |
else |
1673 |
{*onptr = ON_E;*wptr = 0;} |
1674 |
return(t_id); |
1675 |
} |
1676 |
*onptr = ON_E; /* Only on edge 1 */ |
1677 |
*wptr = 1; |
1678 |
return(t_id); |
1679 |
} |
1680 |
else |
1681 |
if(on2 >= -EDGE_EPS) /* Is on edge 2 ? */ |
1682 |
{ |
1683 |
*onptr = ON_E; *wptr = 2; |
1684 |
return(t_id); |
1685 |
} |
1686 |
if(on0 >= -EDGE_EPS) /* Is on edge 0 ? */ |
1687 |
{ |
1688 |
*onptr = ON_E; *wptr = 0; |
1689 |
return(t_id); |
1690 |
} |
1691 |
*onptr = IN_T; /* Must be interior to t */ |
1692 |
return(t_id); |
1693 |
} |
1694 |
} |
1695 |
|
1696 |
#define check_edges(on0,on1,on2,o,w,t_id) \ |
1697 |
if(on0){if(on1){*o = ON_P;*w = 2;} else if(on2){*o = ON_P;*w = 1;} \ |
1698 |
else {*o = ON_E; *w = 0; } return(t_id); } \ |
1699 |
if(on1){if(on2){*o = ON_P;*w = 0;} else {*o = ON_E;*w = 1;}return(t_id);}\ |
1700 |
if(on2){*o = ON_E;*w = 2;return(t_id);} |
1701 |
|
1702 |
#define check_verts(p,v0,v1,v2,o,w,t_id) \ |
1703 |
if(EQUAL_VEC3(v0,p)){ *o = ON_V; *w = 0; return(t_id); } \ |
1704 |
if(EQUAL_VEC3(v1,p)){ *o = ON_V; *w = 1; return(t_id); } \ |
1705 |
if(EQUAL_VEC3(v2,p)){ *o = ON_V; *w = 2; return(t_id);} |
1706 |
|
1707 |
|
1708 |
|
1709 |
find_neighbor(argptr,qt,f,doneptr) |
1710 |
int *argptr; |
1711 |
QUADTREE qt; |
1712 |
FUNC f; |
1713 |
int *doneptr; |
1714 |
{ |
1715 |
S_ID s_id; |
1716 |
int i; |
1717 |
S_ID *optr; |
1718 |
|
1719 |
if(QT_IS_EMPTY(qt)) |
1720 |
return; |
1721 |
else |
1722 |
if(QT_IS_TREE(qt)) |
1723 |
{ |
1724 |
for(i=0;i < 4; i++) |
1725 |
{ |
1726 |
find_neighbor(argptr,QT_NTH_CHILD(qt,i),f,doneptr); |
1727 |
if(*doneptr) |
1728 |
return; |
1729 |
} |
1730 |
} |
1731 |
else |
1732 |
{ |
1733 |
optr = qtqueryset(qt); |
1734 |
for(i = QT_SET_CNT(optr); i > 0; i--) |
1735 |
{ |
1736 |
s_id = QT_SET_NEXT_ELEM(optr); |
1737 |
if(s_id != ((S_ARGS *)argptr)->s_id) |
1738 |
{ |
1739 |
*doneptr = TRUE; |
1740 |
((S_ARGS *)argptr)->n_id = s_id; |
1741 |
return; |
1742 |
} |
1743 |
} |
1744 |
} |
1745 |
} |
1746 |
|
1747 |
smInsert_samp(sm,s_id,p,nptr) |
1748 |
SM *sm; |
1749 |
S_ID s_id; |
1750 |
FVECT p; |
1751 |
S_ID *nptr; |
1752 |
{ |
1753 |
FVECT tpt; |
1754 |
FUNC f; |
1755 |
S_ARGS args; |
1756 |
|
1757 |
F_FUNC(f) = insert_samp; |
1758 |
args.s_id = s_id; |
1759 |
if(nptr) |
1760 |
{ |
1761 |
args.n_id = 1; |
1762 |
F_FUNC2(f) = find_neighbor; |
1763 |
} |
1764 |
else |
1765 |
args.n_id = 0; |
1766 |
F_ARGS(f) = (int *)(&args); |
1767 |
stInsert_samp(SM_LOCATOR(sm),p,f); |
1768 |
|
1769 |
if(nptr) |
1770 |
*nptr = args.n_id; |
1771 |
} |
1772 |
|
1773 |
/* Assumed p is normalized to view sphere */ |
1774 |
int |
1775 |
smSample_locate_tri(sm,p,s_id,onptr,whichptr,nptr) |
1776 |
SM *sm; |
1777 |
FVECT p; |
1778 |
S_ID s_id; |
1779 |
int *onptr,*whichptr; |
1780 |
S_ID *nptr; |
1781 |
{ |
1782 |
int tri_id; |
1783 |
FVECT tpt; |
1784 |
TRI *tri; |
1785 |
|
1786 |
if(SM_S_NTH_QT(sm,s_id) == EMPTY) |
1787 |
smInsert_samp(sm,s_id,p,nptr); |
1788 |
#ifdef DEBUG |
1789 |
if(*nptr == INVALID) |
1790 |
error(CONSISTENCY,"smSample_locate_tri: unable to find sample\n"); |
1791 |
#endif |
1792 |
|
1793 |
/* Get the triangle adjacent to a sample in qt, or if there are no other |
1794 |
samples in qt than the one just inserted, look at siblings-from parent |
1795 |
node |
1796 |
*/ |
1797 |
|
1798 |
tri_id = SM_NTH_VERT(sm,*nptr); |
1799 |
#ifdef DEBUG |
1800 |
if(tri_id == INVALID) |
1801 |
error(CONSISTENCY,"smSample_locate_tri: Invalid tri_id\n"); |
1802 |
#endif |
1803 |
|
1804 |
tri = SM_NTH_TRI(sm,tri_id); |
1805 |
#ifdef DEBUG |
1806 |
Tcnt++; |
1807 |
if(!T_IS_VALID(tri)) |
1808 |
error(CONSISTENCY,"smSample_locate_tri: Invalid tri\n"); |
1809 |
#endif |
1810 |
tri_id = smWalk(sm,p,tri_id,tri,onptr,whichptr,-1,0.0,NULL,NULL); |
1811 |
#ifdef DEBUG |
1812 |
if(tri_id == INVALID) |
1813 |
error(CONSISTENCY,"smSample_locate_tri: unable to find tri on walk\n"); |
1814 |
#endif |
1815 |
return(tri_id); |
1816 |
} |
1817 |
|
1818 |
/* |
1819 |
Determine whether this sample should: |
1820 |
a) be added to the mesh by subdividing the triangle |
1821 |
b) ignored |
1822 |
c) replace values of an existing mesh vertex |
1823 |
|
1824 |
In case a, the routine will return TRUE, for b,c will return FALSE |
1825 |
In case a, also determine if this sample should cause the deletion of |
1826 |
an existing vertex. If so *rptr will contain the id of the sample to delete |
1827 |
after the new sample has been added. |
1828 |
|
1829 |
ASSUMPTION: this will not be called with a new sample that is |
1830 |
a BASE point. |
1831 |
|
1832 |
The following tests are performed (in order) to determine the fate |
1833 |
of the sample: |
1834 |
|
1835 |
1) If the new sample is close in ws, and close in the spherical projection |
1836 |
to one of the triangle vertex samples: |
1837 |
pick the point with dir closest to that of the canonical view |
1838 |
If it is the new point: mark existing point for deletion,and return |
1839 |
TRUE,else return FALSE |
1840 |
2) If the spherical projection of new is < REPLACE_EPS from a base point: |
1841 |
add new and mark the base for deletion: return TRUE |
1842 |
3) If the addition of the new sample point would introduce a "puncture" |
1843 |
or cause new triangles with large depth differences:return FALSE |
1844 |
This attempts to throw out points that should be occluded |
1845 |
*/ |
1846 |
int |
1847 |
smTest_samp(sm,tri_id,dir,p,rptr,ns,n0,n1,n2,ds,d0,on,which) |
1848 |
SM *sm; |
1849 |
int tri_id; |
1850 |
FVECT dir,p; |
1851 |
S_ID *rptr; |
1852 |
FVECT ns,n0,n1,n2; |
1853 |
double ds,d0; |
1854 |
int on,which; |
1855 |
{ |
1856 |
TRI *tri; |
1857 |
double d,d2,dnear,dspt,d01,d12,d20,s0,s1,s2; |
1858 |
double dp,dp1; |
1859 |
S_ID vid[3]; |
1860 |
int i,norm,dcnt,bcnt; |
1861 |
FVECT diff[3],spt,npt,n; |
1862 |
FVECT nearpt; |
1863 |
|
1864 |
*rptr = INVALID; |
1865 |
bcnt = dcnt = 0; |
1866 |
tri = SM_NTH_TRI(sm,tri_id); |
1867 |
vid[0] = T_NTH_V(tri,0); |
1868 |
vid[1] = T_NTH_V(tri,1); |
1869 |
vid[2] = T_NTH_V(tri,2); |
1870 |
|
1871 |
for(i=0; i<3; i++) |
1872 |
{ |
1873 |
if(SM_BASE_ID(sm,vid[i])) |
1874 |
bcnt++; |
1875 |
else |
1876 |
if(SM_DIR_ID(sm,vid[i])) |
1877 |
dcnt++; |
1878 |
} |
1879 |
if(on == ON_P) |
1880 |
{ |
1881 |
FVECT edir; |
1882 |
/* Pick the point with dir closest to that of the canonical view |
1883 |
if it is the new sample: mark existing point for deletion |
1884 |
*/ |
1885 |
if(!dir) |
1886 |
return(FALSE); |
1887 |
if(SM_BASE_ID(sm,vid[which])) |
1888 |
return(FALSE); |
1889 |
if(SM_DIR_ID(sm,vid[which])) |
1890 |
{ |
1891 |
*rptr = vid[which]; |
1892 |
return(TRUE); |
1893 |
} |
1894 |
decodedir(edir,SM_NTH_W_DIR(sm,vid[which])); |
1895 |
if(which == 0) |
1896 |
d = DOT(edir,n0); |
1897 |
else |
1898 |
if(which == 1) |
1899 |
d = DOT(edir,n1); |
1900 |
else |
1901 |
d = DOT(edir,n2); |
1902 |
d2 = DOT(dir,ns); |
1903 |
/* The existing sample is a better sample:punt */ |
1904 |
if(d2 >= d) |
1905 |
return(FALSE); |
1906 |
else |
1907 |
{ |
1908 |
/* The new sample is better: mark existing one for deletion*/ |
1909 |
*rptr = vid[which]; |
1910 |
return(TRUE); |
1911 |
} |
1912 |
} |
1913 |
|
1914 |
/* Now test if sample epsilon is within circumcircle of enclosing tri |
1915 |
if not punt: |
1916 |
*/ |
1917 |
{ |
1918 |
double ab[3],ac[3],r[3]; |
1919 |
|
1920 |
VSUB(ab,n2,n1); |
1921 |
VSUB(ac,n0,n2); |
1922 |
VCROSS(r,ab,ac); |
1923 |
dp = DOT(r,n1); |
1924 |
dp1 = DOT(r,ns); |
1925 |
if(dp1*dp1 + COS_VERT_EPS*DOT(r,r) < dp*dp) |
1926 |
{ |
1927 |
#ifdef DEBUG |
1928 |
eputs("smTest_samp:rejecting samp,cant guarantee not within eps\n"); |
1929 |
#endif |
1930 |
return(FALSE); |
1931 |
} |
1932 |
} |
1933 |
#ifdef DEBUG |
1934 |
#if DEBUG > 1 |
1935 |
if(on == ON_E) |
1936 |
{ |
1937 |
TRI *topp; |
1938 |
int opp_id; |
1939 |
FVECT vopp; |
1940 |
|
1941 |
topp = SM_NTH_TRI(sm,T_NTH_NBR(tri,which)); |
1942 |
opp_id = T_NTH_V(topp, T_NTH_NBR_PTR(tri_id,topp)); |
1943 |
/* first check if valid tri created*/ |
1944 |
VSUB(vopp,SM_NTH_WV(sm,opp_id),SM_VIEW_CENTER(sm)); |
1945 |
normalize(vopp); |
1946 |
VCROSS(n,ns,vopp); |
1947 |
normalize(n); |
1948 |
if(which==2) |
1949 |
dp = DOT(n,n0) * DOT(n,n1); |
1950 |
else |
1951 |
if(which==0) |
1952 |
dp = DOT(n,n1) * DOT(n,n2); |
1953 |
else |
1954 |
dp = DOT(n,n2) * DOT(n,n0); |
1955 |
if(dp > 0.0) |
1956 |
{ |
1957 |
eputs("smInsert_samp_mesh: couldn't split edge: rejecting\n"); |
1958 |
/* test epsilon for edge */ |
1959 |
return(FALSE); |
1960 |
} |
1961 |
} |
1962 |
#endif |
1963 |
#endif |
1964 |
/* TEST 4: |
1965 |
If the addition of the new sample point would introduce a "puncture" |
1966 |
or cause new triangles with large depth differences:dont add: |
1967 |
*/ |
1968 |
if(bcnt || dcnt) |
1969 |
return(TRUE); |
1970 |
|
1971 |
if(ds < d0) |
1972 |
return(TRUE); |
1973 |
|
1974 |
d01 = DIST_SQ(SM_NTH_WV(sm,vid[1]),SM_NTH_WV(sm,vid[0])); |
1975 |
VSUB(diff[0],SM_NTH_WV(sm,vid[0]),p); |
1976 |
s0 = DOT(diff[0],diff[0]); |
1977 |
if(s0 < S_REPLACE_SCALE*d01) |
1978 |
return(TRUE); |
1979 |
|
1980 |
d12 = DIST_SQ(SM_NTH_WV(sm,vid[2]),SM_NTH_WV(sm,vid[1])); |
1981 |
if(s0 < S_REPLACE_SCALE*d12) |
1982 |
return(TRUE); |
1983 |
d20 = DIST_SQ(SM_NTH_WV(sm,vid[0]),SM_NTH_WV(sm,vid[2])); |
1984 |
if(s0 < S_REPLACE_SCALE*d20) |
1985 |
return(TRUE); |
1986 |
d = MIN3(d01,d12,d20); |
1987 |
VSUB(diff[1],SM_NTH_WV(sm,vid[1]),p); |
1988 |
s1 = DOT(diff[1],diff[1]); |
1989 |
if(s1 < S_REPLACE_SCALE*d) |
1990 |
return(TRUE); |
1991 |
VSUB(diff[2],SM_NTH_WV(sm,vid[2]),p); |
1992 |
s2 = DOT(diff[2],diff[2]); |
1993 |
if(s2 < S_REPLACE_SCALE*d) |
1994 |
return(TRUE); |
1995 |
|
1996 |
/* TEST 5: |
1997 |
Check to see if triangle is relatively large and should therefore |
1998 |
be subdivided anyway. |
1999 |
*/ |
2000 |
d0 = d0*d0*DIST_SQ(SM_NTH_WV(sm,vid[1]),SM_VIEW_CENTER(sm)); |
2001 |
d0 *= DIST_SQ(SM_NTH_WV(sm,vid[2]),SM_VIEW_CENTER(sm)); |
2002 |
if (d01*d12*d20/d0 > S_REPLACE_TRI) |
2003 |
return(TRUE); |
2004 |
|
2005 |
return(FALSE); |
2006 |
} |
2007 |
S_ID |
2008 |
smReplace_samp(sm,c,dir,p,np,s_id,t_id,o_id,on,which) |
2009 |
SM *sm; |
2010 |
COLR c; |
2011 |
FVECT dir,p,np; |
2012 |
S_ID s_id; |
2013 |
int t_id; |
2014 |
S_ID o_id; |
2015 |
int on,which; |
2016 |
{ |
2017 |
S_ID v_id; |
2018 |
int tri_id; |
2019 |
TRI *t,*tri; |
2020 |
|
2021 |
tri = SM_NTH_TRI(sm,t_id); |
2022 |
v_id = T_NTH_V(tri,which); |
2023 |
|
2024 |
/* If it is a base id, need new sample */ |
2025 |
if(SM_BASE_ID(sm,v_id)) |
2026 |
return(v_id); |
2027 |
|
2028 |
if(EQUAL_VEC3(p,SM_NTH_WV(sm,v_id))) |
2029 |
return(INVALID); |
2030 |
|
2031 |
if(dir) |
2032 |
{ /* If world point */ |
2033 |
FVECT odir,no; |
2034 |
double d,d1; |
2035 |
int dir_id; |
2036 |
/* if existing point is a not a dir, compare directions */ |
2037 |
if(!(dir_id = SM_DIR_ID(sm,v_id))) |
2038 |
{ |
2039 |
decodedir(odir, SM_NTH_W_DIR(sm,v_id)); |
2040 |
VSUB(no,SM_NTH_WV(sm,v_id),SM_VIEW_CENTER(sm)); |
2041 |
d = DOT(dir,np); |
2042 |
d1 = DOT(odir,np); |
2043 |
/* The existing sample is a better sample:punt */ |
2044 |
} |
2045 |
if(dir_id || (d*d*DOT(no,no) > d1*d1)) |
2046 |
{ |
2047 |
/* The new sample has better information- replace values */ |
2048 |
sInit_samp(SM_SAMP(sm),v_id,c,dir,p,o_id); |
2049 |
if(!SM_IS_NTH_T_NEW(sm,t_id)) |
2050 |
SM_SET_NTH_T_NEW(sm,t_id); |
2051 |
tri_id = smTri_next_ccw_nbr(sm,tri,v_id); |
2052 |
while(tri_id != t_id) |
2053 |
{ |
2054 |
t = SM_NTH_TRI(sm,tri_id); |
2055 |
if(!SM_IS_NTH_T_NEW(sm,tri_id)) |
2056 |
SM_SET_NTH_T_NEW(sm,tri_id); |
2057 |
tri_id = smTri_next_ccw_nbr(sm,t,v_id); |
2058 |
} |
2059 |
} |
2060 |
return(v_id); |
2061 |
} |
2062 |
else /* New point is a dir */ |
2063 |
return(INVALID); |
2064 |
|
2065 |
} |
2066 |
|
2067 |
S_ID |
2068 |
smAlloc_samp(sm) |
2069 |
SM *sm; |
2070 |
{ |
2071 |
S_ID s_id; |
2072 |
int replaced,cnt; |
2073 |
SAMP *s; |
2074 |
FVECT p; |
2075 |
|
2076 |
s = SM_SAMP(sm); |
2077 |
s_id = sAlloc_samp(s,&replaced); |
2078 |
while(replaced) |
2079 |
{ |
2080 |
smRemoveVertex(sm,s_id); |
2081 |
s_id = sAlloc_samp(s,&replaced); |
2082 |
} |
2083 |
return(s_id); |
2084 |
} |
2085 |
|
2086 |
|
2087 |
/* Add sample to the mesh: |
2088 |
|
2089 |
the sample can be a world space or directional point. If o_id !=INVALID, |
2090 |
then we have an existing sample containing the appropriate information |
2091 |
already converted into storage format. |
2092 |
The spherical projection of the point/ray can: |
2093 |
a) coincide with existing vertex |
2094 |
i) conincides with existing sample |
2095 |
ii) projects same as existing sample |
2096 |
iii) hits a base vertex |
2097 |
b) coincide with existing edge |
2098 |
c) Fall in existing triangle |
2099 |
*/ |
2100 |
S_ID |
2101 |
smAdd_samp(sm,c,dir,p,o_id) |
2102 |
SM *sm; |
2103 |
COLR c; |
2104 |
FVECT dir,p; |
2105 |
S_ID o_id; |
2106 |
{ |
2107 |
int t_id,on,which,n_id; |
2108 |
S_ID s_id,r_id,nbr_id; |
2109 |
double ds,d0; |
2110 |
FVECT wpt,ns,n0,n1,n2; |
2111 |
QUADTREE qt,parent; |
2112 |
TRI *t; |
2113 |
|
2114 |
r_id = INVALID; |
2115 |
nbr_id = INVALID; |
2116 |
/* Must do this first-as may change mesh */ |
2117 |
s_id = smAlloc_samp(sm); |
2118 |
SM_S_NTH_QT(sm,s_id)= EMPTY; |
2119 |
/* If sample is a world space point */ |
2120 |
if(p) |
2121 |
{ |
2122 |
VSUB(ns,p,SM_VIEW_CENTER(sm)); |
2123 |
ds = normalize(ns); |
2124 |
while(1) |
2125 |
{ |
2126 |
t_id = smSample_locate_tri(sm,ns,s_id,&on,&which,&nbr_id); |
2127 |
qt = SM_S_NTH_QT(sm,s_id); |
2128 |
if(t_id == INVALID) |
2129 |
{ |
2130 |
#ifdef DEBUG |
2131 |
eputs("smAddSamp(): unable to locate tri containing sample \n"); |
2132 |
#endif |
2133 |
smUnalloc_samp(sm,s_id); |
2134 |
qtremovelast(qt,s_id); |
2135 |
return(INVALID); |
2136 |
} |
2137 |
/* If spherical projection coincides with existing sample: replace */ |
2138 |
if(on == ON_V) |
2139 |
{ |
2140 |
n_id = smReplace_samp(sm,c,dir,p,ns,s_id,t_id,o_id,on,which); |
2141 |
if(n_id != s_id) |
2142 |
{ |
2143 |
smUnalloc_samp(sm,s_id); |
2144 |
#if 0 |
2145 |
fprintf(stderr,"Unallocating sample %d\n",s_id); |
2146 |
#endif |
2147 |
qtremovelast(qt,s_id); |
2148 |
} |
2149 |
return(n_id); |
2150 |
} |
2151 |
t = SM_NTH_TRI(sm,t_id); |
2152 |
VSUB(n0,SM_NTH_WV(sm,T_NTH_V(t,0)),SM_VIEW_CENTER(sm)); |
2153 |
d0 = normalize(n0); |
2154 |
VSUB(n1,SM_NTH_WV(sm,T_NTH_V(t,1)),SM_VIEW_CENTER(sm)); |
2155 |
normalize(n1); |
2156 |
VSUB(n2,SM_NTH_WV(sm,T_NTH_V(t,2)),SM_VIEW_CENTER(sm)); |
2157 |
normalize(n2); |
2158 |
if((!(smTest_samp(sm,t_id,dir,p,&r_id,ns,n0,n1,n2,ds,d0,on,which)))) |
2159 |
{ |
2160 |
smUnalloc_samp(sm,s_id); |
2161 |
#if 0 |
2162 |
fprintf(stderr,"Unallocating sample %d\n",s_id); |
2163 |
#endif |
2164 |
qtremovelast(qt,s_id); |
2165 |
return(INVALID); |
2166 |
} |
2167 |
if(r_id != INVALID) |
2168 |
{ |
2169 |
smRemoveVertex(sm,r_id); |
2170 |
if(nbr_id == r_id) |
2171 |
{ |
2172 |
qtremovelast(qt,s_id); |
2173 |
SM_S_NTH_QT(sm,s_id) = EMPTY; |
2174 |
} |
2175 |
} |
2176 |
else |
2177 |
break; |
2178 |
} |
2179 |
/* If sample is being added in the middle of the sample array: tone |
2180 |
map individually |
2181 |
*/ |
2182 |
/* If not base or sky point, add distance from center to average*/ |
2183 |
smDist_sum += 1.0/ds; |
2184 |
/* Initialize sample */ |
2185 |
sInit_samp(SM_SAMP(sm),s_id,c,dir,p,o_id); |
2186 |
smInsert_samp_mesh(sm,s_id,t_id,ns,n0,n1,n2,on,which); |
2187 |
} |
2188 |
/* If sample is a direction vector */ |
2189 |
else |
2190 |
{ |
2191 |
VADD(wpt,dir,SM_VIEW_CENTER(sm)); |
2192 |
/* Allocate space for a sample and initialize */ |
2193 |
while(1) |
2194 |
{ |
2195 |
t_id = smSample_locate_tri(sm,dir,s_id,&on,&which,&nbr_id); |
2196 |
qt = SM_S_NTH_QT(sm,s_id); |
2197 |
#ifdef DEBUG |
2198 |
if(t_id == INVALID) |
2199 |
{ |
2200 |
eputs("smAddSamp():can't locate tri containing samp\n"); |
2201 |
smUnalloc_samp(sm,s_id); |
2202 |
qtremovelast(qt,s_id); |
2203 |
return(INVALID); |
2204 |
} |
2205 |
#endif |
2206 |
if(on == ON_V) |
2207 |
{ |
2208 |
smUnalloc_samp(sm,s_id); |
2209 |
qtremovelast(qt,s_id); |
2210 |
return(INVALID); |
2211 |
} |
2212 |
t = SM_NTH_TRI(sm,t_id); |
2213 |
VSUB(n0,SM_NTH_WV(sm,T_NTH_V(t,0)),SM_VIEW_CENTER(sm)); |
2214 |
d0 = normalize(n0); |
2215 |
VSUB(n1,SM_NTH_WV(sm,T_NTH_V(t,1)),SM_VIEW_CENTER(sm)); |
2216 |
normalize(n1); |
2217 |
VSUB(n2,SM_NTH_WV(sm,T_NTH_V(t,2)),SM_VIEW_CENTER(sm)); |
2218 |
normalize(n2); |
2219 |
if(!smTest_samp(sm,t_id,NULL,wpt,&r_id,dir,n0,n1,n2,1.0,d0,on,which)) |
2220 |
{ |
2221 |
smUnalloc_samp(sm,s_id); |
2222 |
qtremovelast(qt,s_id); |
2223 |
return(INVALID); |
2224 |
} |
2225 |
if(r_id != INVALID) |
2226 |
{ |
2227 |
smRemoveVertex(sm,r_id); |
2228 |
if(nbr_id == r_id) |
2229 |
{ |
2230 |
qtremovelast(qt,s_id); |
2231 |
SM_S_NTH_QT(sm,s_id) = EMPTY; |
2232 |
} |
2233 |
} |
2234 |
else |
2235 |
break; |
2236 |
} |
2237 |
sInit_samp(SM_SAMP(sm),s_id,c,NULL,wpt,o_id); |
2238 |
smInsert_samp_mesh(sm,s_id,t_id,dir,n0,n1,n2,on,which); |
2239 |
} |
2240 |
return(s_id); |
2241 |
} |
2242 |
|
2243 |
/* |
2244 |
* int |
2245 |
* smNewSamp(c, dir, p) : register new sample point and return index |
2246 |
* COLR c; : pixel color (RGBE) |
2247 |
* FVECT dir; : ray direction vector |
2248 |
* FVECT p; : world intersection point |
2249 |
* |
2250 |
* Add new sample point to data structures, removing old values as necessary. |
2251 |
* New sample representation will be output in next call to smUpdate(). |
2252 |
* If the point is a sky point: then v=NULL |
2253 |
*/ |
2254 |
#define FVECT_TO_SFLOAT(p) \ |
2255 |
(p[0]=(SFLOAT)p[0],p[1]=(SFLOAT)p[1],p[2]=(SFLOAT)p[2]) |
2256 |
int |
2257 |
smNewSamp(c,dir,p) |
2258 |
COLR c; |
2259 |
FVECT dir; |
2260 |
FVECT p; |
2261 |
{ |
2262 |
S_ID s_id; |
2263 |
|
2264 |
/* First check if this the first sample: if so initialize mesh */ |
2265 |
if(SM_NUM_SAMP(smMesh) == 0) |
2266 |
{ |
2267 |
smInit_sm(smMesh,odev.v.vp); |
2268 |
sClear_all_flags(SM_SAMP(smMesh)); |
2269 |
} |
2270 |
FVECT_TO_SFLOAT(p); |
2271 |
FVECT_TO_SFLOAT(dir); |
2272 |
/* Add the sample to the mesh */ |
2273 |
s_id = smAdd_samp(smMesh,c,dir,p,INVALID); |
2274 |
|
2275 |
return((int)s_id); |
2276 |
|
2277 |
} |
2278 |
S_ID |
2279 |
smAdd_base_vertex(sm,v) |
2280 |
SM *sm; |
2281 |
FVECT v; |
2282 |
{ |
2283 |
S_ID id; |
2284 |
|
2285 |
/* First add coordinate to the sample array */ |
2286 |
id = sAdd_base_point(SM_SAMP(sm),v); |
2287 |
if(id == INVALID) |
2288 |
return(INVALID); |
2289 |
/* Initialize triangle pointer to -1 */ |
2290 |
smClear_vert(sm,id); |
2291 |
return(id); |
2292 |
} |
2293 |
|
2294 |
|
2295 |
|
2296 |
/* Initialize a the point location DAG based on a 6 triangle tesselation |
2297 |
of the unit sphere centered on the view center. The DAG structure |
2298 |
contains 6 roots: one for each initial base triangle |
2299 |
*/ |
2300 |
|
2301 |
int |
2302 |
smCreate_base_mesh(sm,type) |
2303 |
SM *sm; |
2304 |
int type; |
2305 |
{ |
2306 |
int i,s_id,tri_id,nbr_id; |
2307 |
S_ID p[SM_BASE_POINTS]; |
2308 |
int ids[SM_BASE_TRIS]; |
2309 |
S_ID v0_id,v1_id,v2_id; |
2310 |
FVECT d,pt,cntr,v0,v1,v2; |
2311 |
TRI *t; |
2312 |
|
2313 |
/* First insert the base vertices into the sample point array */ |
2314 |
for(i=0; i < SM_BASE_POINTS; i++) |
2315 |
{ |
2316 |
VADD(cntr,icosa_verts[i],SM_VIEW_CENTER(sm)); |
2317 |
p[i] = smAdd_base_vertex(sm,cntr); |
2318 |
smInsert_samp(sm,p[i],icosa_verts[i],NULL); |
2319 |
} |
2320 |
/* Create the base triangles */ |
2321 |
for(i=0;i < SM_BASE_TRIS; i++) |
2322 |
{ |
2323 |
v0_id = p[icosa_tris[i][0]]; |
2324 |
v1_id = p[icosa_tris[i][1]]; |
2325 |
v2_id = p[icosa_tris[i][2]]; |
2326 |
ids[i] = smAdd_tri(sm, v0_id,v1_id,v2_id,&t); |
2327 |
/* Set neighbors */ |
2328 |
for(nbr_id=0; nbr_id < 3; nbr_id++) |
2329 |
T_NTH_NBR(SM_NTH_TRI(sm,ids[i]),nbr_id) = icosa_nbrs[i][nbr_id]; |
2330 |
|
2331 |
} |
2332 |
return(1); |
2333 |
|
2334 |
} |
2335 |
|
2336 |
smRebuild(sm,v) |
2337 |
SM *sm; |
2338 |
VIEW *v; |
2339 |
{ |
2340 |
S_ID s_id; |
2341 |
int j,cnt; |
2342 |
FVECT p,ov,dir; |
2343 |
double d; |
2344 |
|
2345 |
#ifdef DEBUG |
2346 |
fprintf(stderr,"smRebuild(): rebuilding...."); |
2347 |
#endif |
2348 |
smCull(sm,v,SM_ALL_LEVELS); |
2349 |
/* Clear the mesh- and rebuild using the current sample array */ |
2350 |
/* Remember the current number of samples */ |
2351 |
cnt = SM_NUM_SAMP(sm); |
2352 |
/* Calculate the difference between the current and new viewpoint*/ |
2353 |
/* Will need to subtract this off of sky points */ |
2354 |
VCOPY(ov,SM_VIEW_CENTER(sm)); |
2355 |
|
2356 |
/* Initialize the mesh to 0 samples and the base triangles */ |
2357 |
smInit_sm(sm,v->vp); |
2358 |
/* Go through all samples and add in if in the new view frustum, and |
2359 |
the dir is <= 30 degrees from new view |
2360 |
*/ |
2361 |
for(s_id=0; s_id < cnt; s_id++) |
2362 |
{ |
2363 |
/* First check if sample visible(conservative approx: if one of tris |
2364 |
attached to sample is in frustum) */ |
2365 |
if(!S_IS_FLAG(s_id)) |
2366 |
continue; |
2367 |
|
2368 |
/* Next test if direction > 30 degrees from current direction */ |
2369 |
if(SM_NTH_W_DIR(sm,s_id)!=-1) |
2370 |
{ |
2371 |
VSUB(p,SM_NTH_WV(sm,s_id),v->vp); |
2372 |
decodedir(dir,SM_NTH_W_DIR(sm,s_id)); |
2373 |
d = DOT(dir,p); |
2374 |
if (d*d < MAXDIFF2*DOT(p,p)) |
2375 |
continue; |
2376 |
VCOPY(p,SM_NTH_WV(sm,s_id)); |
2377 |
smAdd_samp(sm,NULL,dir,p,s_id); |
2378 |
} |
2379 |
else |
2380 |
{ |
2381 |
/* If the direction is > 45 degrees from current view direction: |
2382 |
throw out |
2383 |
*/ |
2384 |
VSUB(dir,SM_NTH_WV(sm,s_id),ov); |
2385 |
if(DOT(dir,v->vdir) < MAXDIR) |
2386 |
continue; |
2387 |
|
2388 |
VADD(SM_NTH_WV(sm,s_id),dir,SM_VIEW_CENTER(sm)); |
2389 |
smAdd_samp(sm,NULL,dir,NULL,s_id); |
2390 |
} |
2391 |
|
2392 |
} |
2393 |
#ifdef DEBUG |
2394 |
fprintf(stderr,"smRebuild():done\n"); |
2395 |
#endif |
2396 |
} |
2397 |
|
2398 |
/* OS is constrained to be <= QT_MAXCSET : if the set exceeds this, the |
2399 |
results of check_set are conservative |
2400 |
*/ |
2401 |
int |
2402 |
compare_ids(id1,id2) |
2403 |
S_ID *id1,*id2; |
2404 |
{ |
2405 |
int d; |
2406 |
|
2407 |
d = *id2-*id1; |
2408 |
|
2409 |
if(d > 0) |
2410 |
return(-1); |
2411 |
if(d < 0) |
2412 |
return(1); |
2413 |
|
2414 |
return(0); |
2415 |
} |
2416 |
|
2417 |
|
2418 |
null_func(argptr,root,qt,n) |
2419 |
int *argptr; |
2420 |
int root; |
2421 |
QUADTREE qt; |
2422 |
int n; |
2423 |
{ |
2424 |
/* do nothing */ |
2425 |
} |
2426 |
|
2427 |
mark_active_samples(argptr,root,qt,n) |
2428 |
int *argptr; |
2429 |
int root; |
2430 |
QUADTREE qt; |
2431 |
int n; |
2432 |
{ |
2433 |
S_ID *os,s_id; |
2434 |
register int i,t_id,tri_id; |
2435 |
TRI *tri; |
2436 |
|
2437 |
if(QT_IS_EMPTY(qt) || QT_LEAF_IS_FLAG(qt)) |
2438 |
return; |
2439 |
|
2440 |
/* For each triangle in the set, set the which flag*/ |
2441 |
os = qtqueryset(qt); |
2442 |
|
2443 |
for (i = QT_SET_CNT(os); i > 0; i--) |
2444 |
{ |
2445 |
s_id = QT_SET_NEXT_ELEM(os); |
2446 |
S_SET_FLAG(s_id); |
2447 |
|
2448 |
tri_id = SM_NTH_VERT(smMesh,s_id); |
2449 |
/* Set the active flag for all adjacent triangles */ |
2450 |
tri = SM_NTH_TRI(smMesh,tri_id); |
2451 |
SM_SET_NTH_T_ACTIVE(smMesh,tri_id); |
2452 |
while((t_id = smTri_next_ccw_nbr(smMesh,tri,s_id)) != tri_id) |
2453 |
{ |
2454 |
tri = SM_NTH_TRI(smMesh,t_id); |
2455 |
SM_SET_NTH_T_ACTIVE(smMesh,t_id); |
2456 |
} |
2457 |
} |
2458 |
} |
2459 |
|
2460 |
smCull(sm,view,n) |
2461 |
SM *sm; |
2462 |
VIEW *view; |
2463 |
int n; |
2464 |
{ |
2465 |
FVECT nr[4],far[4]; |
2466 |
FPEQ peq; |
2467 |
int debug=0; |
2468 |
FUNC f; |
2469 |
|
2470 |
/* First clear all the quadtree node flags */ |
2471 |
qtClearAllFlags(); |
2472 |
|
2473 |
F_ARGS(f) = NULL; |
2474 |
/* If marking samples down to leaves */ |
2475 |
if(n == SM_ALL_LEVELS) |
2476 |
{ |
2477 |
/* Mark triangles in approx. view frustum as being active:set |
2478 |
LRU counter: for use in discarding samples when out |
2479 |
of space |
2480 |
*/ |
2481 |
F_FUNC(f) = mark_active_samples; |
2482 |
smClear_flags(sm,T_ACTIVE_FLAG); |
2483 |
/* Clear all of the active sample flags*/ |
2484 |
sClear_all_flags(SM_SAMP(sm)); |
2485 |
} |
2486 |
else |
2487 |
/* Just mark qtree flags */ |
2488 |
F_FUNC(f) = null_func; |
2489 |
|
2490 |
/* calculate the world space coordinates of the view frustum: |
2491 |
Radiance often has no far clipping plane: but driver will set |
2492 |
dev_zmin,dev_zmax to satisfy OGL |
2493 |
*/ |
2494 |
calculate_view_frustum(view->vp,view->hvec,view->vvec,view->horiz, |
2495 |
view->vert, dev_zmin,dev_zmax,nr,far); |
2496 |
|
2497 |
#ifdef TEST_DRIVER |
2498 |
VCOPY(FrustumFar[0],far[0]); |
2499 |
VCOPY(FrustumFar[1],far[1]); |
2500 |
VCOPY(FrustumFar[2],far[2]); |
2501 |
VCOPY(FrustumFar[3],far[3]); |
2502 |
VCOPY(FrustumNear[0],nr[0]); |
2503 |
VCOPY(FrustumNear[1],nr[1]); |
2504 |
VCOPY(FrustumNear[2],nr[2]); |
2505 |
VCOPY(FrustumNear[3],nr[3]); |
2506 |
#endif |
2507 |
/* Project the view frustum onto the spherical quadtree */ |
2508 |
/* For every cell intersected by the projection of the faces |
2509 |
|
2510 |
of the frustum: mark all triangles in the cell as ACTIVE- |
2511 |
Also set the triangles LRU clock counter |
2512 |
*/ |
2513 |
|
2514 |
if(EQUAL_VEC3(view->vp,SM_VIEW_CENTER(sm))) |
2515 |
{/* Near face triangles */ |
2516 |
|
2517 |
smLocator_apply(sm,nr[0],nr[2],nr[3],f,n); |
2518 |
smLocator_apply(sm,nr[2],nr[0],nr[1],f,n); |
2519 |
return; |
2520 |
} |
2521 |
/* Test the view against the planes: and swap orientation if inside:*/ |
2522 |
tri_plane_equation(nr[0],nr[2],nr[3], &peq,FALSE); |
2523 |
if(PT_ON_PLANE(SM_VIEW_CENTER(sm),peq) < 0.0) |
2524 |
{/* Near face triangles */ |
2525 |
smLocator_apply(sm,nr[3],nr[2],nr[0],f,n); |
2526 |
smLocator_apply(sm,nr[1],nr[0],nr[2],f,n); |
2527 |
} |
2528 |
else |
2529 |
{/* Near face triangles */ |
2530 |
smLocator_apply(sm,nr[0],nr[2],nr[3],f,n); |
2531 |
smLocator_apply(sm,nr[2],nr[0],nr[1],f,n); |
2532 |
} |
2533 |
tri_plane_equation(nr[0],far[3],far[0], &peq,FALSE); |
2534 |
if(PT_ON_PLANE(SM_VIEW_CENTER(sm),peq) < 0.0) |
2535 |
{ /* Right face triangles */ |
2536 |
smLocator_apply(sm,far[0],far[3],nr[0],f,n); |
2537 |
smLocator_apply(sm,nr[3],nr[0],far[3],f,n); |
2538 |
} |
2539 |
else |
2540 |
{/* Right face triangles */ |
2541 |
smLocator_apply(sm,nr[0],far[3],far[0],f,n); |
2542 |
smLocator_apply(sm,far[3],nr[0],nr[3],f,n); |
2543 |
} |
2544 |
|
2545 |
tri_plane_equation(nr[1],far[2],nr[2], &peq,FALSE); |
2546 |
if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) < 0.0) |
2547 |
{ /* Left face triangles */ |
2548 |
smLocator_apply(sm,nr[2],far[2],nr[1],f,n); |
2549 |
smLocator_apply(sm,far[1],nr[1],far[2],f,n); |
2550 |
} |
2551 |
else |
2552 |
{ /* Left face triangles */ |
2553 |
smLocator_apply(sm,nr[1],far[2],nr[2],f,n); |
2554 |
smLocator_apply(sm,far[2],nr[1],far[1],f,n); |
2555 |
} |
2556 |
tri_plane_equation(nr[0],far[0],nr[1], &peq,FALSE); |
2557 |
if(PT_ON_PLANE(SM_VIEW_CENTER(sm),peq) < 0.0) |
2558 |
{/* Top face triangles */ |
2559 |
smLocator_apply(sm,nr[1],far[0],nr[0],f,n); |
2560 |
smLocator_apply(sm,far[1],far[0],nr[1],f,n); |
2561 |
} |
2562 |
else |
2563 |
{/* Top face triangles */ |
2564 |
smLocator_apply(sm,nr[0],far[0],nr[1],f,n); |
2565 |
smLocator_apply(sm,nr[1],far[0],far[1],f,n); |
2566 |
} |
2567 |
tri_plane_equation(nr[3],nr[2],far[3], &peq,FALSE); |
2568 |
if(PT_ON_PLANE(SM_VIEW_CENTER(sm),peq) < 0.0) |
2569 |
{/* Bottom face triangles */ |
2570 |
smLocator_apply(sm,far[3],nr[2],nr[3],f,n); |
2571 |
smLocator_apply(sm,far[3],far[2],nr[2],f,n); |
2572 |
} |
2573 |
else |
2574 |
{ /* Bottom face triangles */ |
2575 |
smLocator_apply(sm,nr[3],nr[2],far[3],f,n); |
2576 |
smLocator_apply(sm,nr[2],far[2],far[3],f,n); |
2577 |
} |
2578 |
tri_plane_equation(far[2],far[0],far[1], &peq,FALSE); |
2579 |
if(PT_ON_PLANE(SM_VIEW_CENTER(sm),peq) < 0.0) |
2580 |
{/* Far face triangles */ |
2581 |
smLocator_apply(sm,far[0],far[2],far[1],f,n); |
2582 |
smLocator_apply(sm,far[2],far[0],far[3],f,n); |
2583 |
} |
2584 |
else |
2585 |
{/* Far face triangles */ |
2586 |
smLocator_apply(sm,far[1],far[2],far[0],f,n); |
2587 |
smLocator_apply(sm,far[3],far[0],far[2],f,n); |
2588 |
} |
2589 |
|
2590 |
} |
2591 |
|
2592 |
|
2593 |
|
2594 |
|
2595 |
|
2596 |
|
2597 |
|
2598 |
|
2599 |
|
2600 |
|
2601 |
|
2602 |
|
2603 |
|
2604 |
|
2605 |
|
2606 |
|
2607 |
|
2608 |
|
2609 |
|
2610 |
|