Panda3D
Loading...
Searching...
No Matches
isoPlacer.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file isoPlacer.cxx
10 * @author drose
11 * @date 2003-10-13
12 */
13
14#include "isoPlacer.h"
15#include "qtessSurface.h"
16#include "subdivSegment.h"
17#include "nurbsSurfaceResult.h"
18#include "pvector.h"
19
20
21/**
22 *
23 */
24void IsoPlacer::
25get_scores(int subdiv, int across, double ratio,
26 NurbsSurfaceResult *surf, bool s) {
27 _maxi = subdiv - 1;
28
29 _cscore.clear();
30 _sscore.clear();
31
32 _cscore.reserve(_maxi);
33 _sscore.reserve(_maxi);
34
35 // First, tally up the curvature and stretch scores across the surface.
36 int i = 0;
37 for (i = 0; i < _maxi; i++) {
38 _cscore.push_back(0.0);
39 _sscore.push_back(0.0);
40 }
41
42 int a;
43 for (a = 0; a <= across; a++) {
44 double v = (double)a / (double)across;
45
46 LVecBase3 p1, p2, p3, pnext;
47 LVecBase3 v1, v2;
48 if (s) {
49 surf->eval_point(0.0, v, p3);
50 } else {
51 surf->eval_point(v, 0.0, p3);
52 }
53 int num_points = 1;
54
55 for (i = -1; i < _maxi; i++) {
56 double u = (double)(i+1) / (double)(_maxi+1);
57 if (s) {
58 surf->eval_point(u, v, pnext);
59 } else {
60 surf->eval_point(v, u, pnext);
61 }
62
63 // We'll ignore consecutive equal points. They don't contribute to
64 // curvature or size.
65 if (!pnext.almost_equal(p3)) {
66 num_points++;
67 p1 = p2;
68 p2 = p3;
69 p3 = pnext;
70
71 v1 = v2;
72 v2 = p3 - p2;
73 double vlength = length(v2);
74 v2 /= vlength;
75
76 if (i >= 0) {
77 _sscore[i] += vlength;
78 }
79
80 if (num_points >= 3) {
81 // We only have a meaningful v1, v2 when we've read at least three
82 // non-equal points.
83 double d = v1.dot(v2);
84
85 _cscore[i] += acos(std::max(std::min(d, 1.0), -1.0));
86 }
87 }
88 }
89 }
90
91 // Now integrate.
92 _cint.clear();
93 _cint.reserve(_maxi + 1);
94
95 double net = 0.0;
96 double ad = (double)(across+1);
97 _cint.push_back(0.0);
98 for (i = 0; i < _maxi; i++) {
99 net += _cscore[i]/ad + ratio * _sscore[i]/ad;
100 _cint.push_back(net);
101 }
102}
103
104/**
105 *
106 */
107void IsoPlacer::
108place(int count, pvector<double> &iso_points) {
109 //int i;
110
111 /*
112 // Count up the average curvature.
113 double avg_curve = 0.0;
114 for (i = 0; i < _maxi; i++) {
115 avg_curve += _cscore[i];
116 }
117 avg_curve /= (double)_maxi;
118 */
119
120 // Find all the local maxima in the curvature table. These are bend points.
121 typedef pvector<int> BendPoints;
122 BendPoints bpoints;
123 BendPoints::iterator bi, bnext;
124
125 typedef pvector<SubdivSegment> Segments;
126 Segments segments;
127 Segments::iterator si;
128
129 /*
130 // Having problems with bend points right now. Maybe this is just a bad
131 // idea. It seems to work pretty well without them, anyway.
132 for (i = 1; i < _maxi-1; i++) {
133 // A point must be measurably higher than both its neighbors, as well as
134 // at least 50% more curvy than the average curvature, to qualify as a
135 // bend point.
136 if (_cscore[i] > _cscore[i-1]+0.001 &&
137 _cscore[i] > _cscore[i+1]+0.001 &&
138 _cscore[i] > 1.5 * avg_curve) {
139 bpoints.push_back(i);
140 }
141 }
142 */
143
144 // Now make sure there aren't any two bend points closer together than
145 // maxicount. If there are, remove the smaller of the two.
146 bi = bpoints.begin();
147 int min_separation = _maxi/count;
148 while (bi != bpoints.end()) {
149 bnext = bi;
150 ++bnext;
151
152 if (bnext != bpoints.end() && (*bnext) - (*bi) < min_separation) {
153 // Too close. Remove one.
154 if (_cscore[*bnext] > _cscore[*bi]) {
155 *bi = *bnext;
156 }
157 bpoints.erase(bnext);
158 } else {
159 // Not too close; keep going;
160 bi = bnext;
161 }
162 }
163
164 // Now, if we have fewer total subdivisions than bend points, then remove
165 // the smallest bend points.
166 while (count - 1 < (int)bpoints.size()) {
167 bi = bpoints.begin();
168 BendPoints::iterator mi = bi;
169 for (++bi; bi != bpoints.end(); ++bi) {
170 if (_cscore[*bi] < _cscore[*mi]) {
171 mi = bi;
172 }
173 }
174 bpoints.erase(mi);
175 }
176
177 // Now all the remaining bend points are valid.
178 bi = bpoints.begin();
179 int last = 0;
180 for (bi = bpoints.begin(); bi != bpoints.end(); ++bi) {
181 segments.push_back(SubdivSegment(&_cint[0], last, *bi));
182 last = *bi;
183 }
184 segments.push_back(SubdivSegment(&_cint[0], last, _maxi));
185
186 int nr = count - segments.size();
187
188 // Now we have subdivided the curve into a number of smaller curves at the
189 // bend points. We still have nr remaining cuts to make; distribute these
190 // cuts among the curves evenly according to score.
191
192 // Divvy out the extra cuts. First, each segment gets an amount
193 // proportional to its score.
194 double net_score = _cint[_maxi];
195 nassertv(net_score > 0.0);
196 int ns = 0;
197 for (si = segments.begin(); si != segments.end(); ++si) {
198 (*si)._num_cuts = (int)floor(nr * (*si).get_score() / net_score);
199 nassertv((*si)._num_cuts <= nr); // This fails if net_score is nan.
200 ns += (*si)._num_cuts;
201 }
202
203 // Then, assign the remaining cuts to the neediest segments.
204 nr -= ns;
205 while (nr > 0) {
206 si = min_element(segments.begin(), segments.end());
207 (*si)._num_cuts++;
208 nr--;
209 }
210
211 // Now cut up the segments as indicated.
212 for (si = segments.begin(); si != segments.end(); ++si) {
213 (*si).cut();
214 }
215
216 // Finally, return the result.
217 iso_points.erase(iso_points.begin(), iso_points.end());
218
219 iso_points.push_back(0.0);
220 for (si = segments.begin(); si != segments.end(); ++si) {
222 for (ci = (*si)._cuts.begin(); ci != (*si)._cuts.end(); ++ci) {
223 iso_points.push_back((*ci+1) / (double)(_maxi+1));
224 }
225 iso_points.push_back(((*si)._t+1) / (double)(_maxi+1));
226 }
227
228 // Oh, wait. The last segment is actually drawn all the way to 1.
229 iso_points.back() = 1.0;
230}
The result of a NurbsSurfaceEvaluator.
bool eval_point(PN_stdfloat u, PN_stdfloat v, LVecBase3 &point)
Computes the point on the surface corresponding to the indicated value in parametric time.
Represents a single hypothetical subdivided segment, under consideration by the IsoPlacer.
This is our own Panda specialization on the default STL vector.
Definition pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.