File: band.cmd

package info (click to toggle)
evolver 2.70+ds-4
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 17,148 kB
  • sloc: ansic: 127,395; makefile: 209; sh: 98
file content (201 lines) | stat: -rw-r--r-- 6,712 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// band.cmd
// Surface Evolver command to create triangulated band bordering
// deisgnated edges and vertices.  Purpose is to make extremely
// accurate PostScript files without notching on thick edges.

// WARNING: This command modifies the surface by creating a lot of
// tiny facets.  You should use only on a disposable copy of your surface.

/* Assumptions:
     3D soapfilm model.
     Linear model.
*/
// Usage: set bandcolor and bandwidth to desired values; bandwidth is
//           the width of the band in surface coordinates on one
//           side of an edge.
//        set the edge attribute inband to nonzero for those edges
//           to have band drawn along them.
//        run makeband

/* To make PostScript file of the resulting surface, do like this:
      Enter command: show edge where 0
      Enter command: P 3
      Show grid lines? n
      Do colors? y
      Do labels? (i for ids, o for originals) n
      Enter file name (.ps will be added): xxx.ps

      or in scripts:
         show edge where 0;
         ps_gridflag off;
         ps_colorflag on;
         ps_labelflag off;
         postscript "xxx.ps"
*/

// IMPORTANT NOTE:  The algorithm may have trouble where inband edges meet
// at an angle, since each vertex has a single band distance attribute
// and the vertex may be a neighbor to two different bands.  This results
// in ragged bands near corners.  A cure is to do banding in stages,
// doing one "original" edge at a time.  But try banding all desired edges
// at once, since you may not have any trouble.

// Not wise to run more than once along a given edge.  Numerical
// variations due to new vertices lead to a lot more unnecessary
// refinements.

define edge attribute inband integer     // 1 if band center, 0 if not
define vertex attribute banddist real    // distance from band center.
define facet attribute bandused integer  // so use each facet at most once
define vertex attribute band_generation integer

bandcolor := black  // Set this to desired color before makeband.
bandwidth := 0.010  // Set this to desired half-width before makeband.


init_bandcalc := {
   // initialize vertex distances from band
   maxbanddist := 100000*bandwidth;
   set vertex banddist maxbanddist;
   set vertex band_generation 100000;
   foreach edge ee where inband do 
   { set ee.vertex banddist 0;
     set ee.vertex band_generation 0;
   };

   // Refine any edge whose endpoints are in band center but edge is not
   foreach edge ee where (ee.inband==0) and (ee.vertex[1].banddist==0)
       and (ee.vertex[2].banddist==0)  
    do { refine ee; ee.vertex[2].banddist := maxbanddist; } ;

}

function integer calc_v_banddist(integer vv_id)
{ local changed,ddiff,ss1,ss2,lambda1,lambda2;
  local xx,yy,newd,ddd;

  changed := 0;
  foreach vertex[vv_id] vv do
  {
       foreach vv.edge ee where ee.vertex[2].banddist < bandwidth do
       { foreach ee.vertex[2].edge eee where eee.id != ee.id and
                eee.vertex[2].banddist < maxbanddist do
         { 

           ddiff := eee.vertex[2].banddist - eee.vertex[1].banddist;
           ss1 := eee.length;
           if abs(ddiff) > ss1*1.0000000001 then
           { // wrapping around something
             if ddiff > 0 then
               eee.vertex[2].banddist := eee.vertex[1].banddist + ss1
             else
               eee.vertex[1].banddist := eee.vertex[2].banddist + ss1;
             changed += 1;
             continue;
           }
           else if abs(ddiff) == ss1 then continue;
           
           ss2 := ee.length;
           lambda1 := -(ee.edge_vector * eee.edge_vector)/ss1^2;
           lambda2 := sqrt(ss2^2 - lambda1^2*ss1^2);
           xx := lambda1*ss1*sqrt(ss1^2 - ddiff^2)/ss1 - lambda2*ddiff/ss1;
           yy := lambda1*ss1*ddiff/ss1 + lambda2*sqrt(ss1^2-ddiff^2)/ss1;
           if xx < 0 then
           { // add radius from tail
             newd := eee.vertex[1].banddist + ss2;
           }
           else if xx > sqrt(ss1^2 - ddiff^2) then
           { // add radius from head
             ddd := (vv.__x - eee.vertex[2].__x)*(vv.__x - eee.vertex[2].__x); 
             newd := eee.vertex[2].banddist + sqrt(ddd);
           }
           else 
           { // between endpoints
             newd := eee.vertex[1].banddist + yy;
           };
           if newd < vv.banddist*0.99999999 then 
           { vv.banddist := newd;
             changed += 1;
           }
         };
       }
  };
  return changed;
}


calc_banddist := {

   local changed,this_generation;

   init_bandcalc;

   // Calculate vertex distances from band center, using
   // only vertices of previous generation, to prevent using
   // vertex distance value that is not finalized yet. 
   for ( this_generation := 1 ; ; this_generation += 1 ) 
   { changed := 0;
     foreach vertex vv where banddist > 0 do
     {
       changed += calc_v_banddist(vv.id);
     };
     if not changed then break;
   };

} // end calc_band_dist

makeband := {
   local eps;

   calc_banddist;

   // Subdivide edges spanning band boundary
   eps := 1e-4*bandwidth;  // numerical margin for error
   foreach edge ee do
   { local d1,d2;
     local new_x,new_y,new_z;
     local lambda;

     d1 := ee.vertex[1].banddist;
     d2 := ee.vertex[2].banddist;
     if ( ((d1<=bandwidth+eps)&&(d2<=bandwidth+eps)) || 
           ((d1>=bandwidth-eps)&&(d2>=bandwidth-eps)))
       then continue;
     lambda := (d1 - bandwidth)/(d1 - d2);
     if ( lambda < .00001 or lambda > .99999 ) then continue;
     new_x := ee.vertex[1].x + lambda*ee.x;  // suitable for torus model
     new_y := ee.vertex[1].y + lambda*ee.y;
     new_z := ee.vertex[1].z + lambda*ee.z;
     refine ee;
     ee.vertex[2].x := new_x;
     ee.vertex[2].y := new_y;
     ee.vertex[2].z := new_z;
     ee.vertex[2].banddist := bandwidth;
   };

   // Color band triangles
   foreach facet ff do
   { if avg(ff.vertex,banddist) < bandwidth then set ff color bandcolor; };

}

// to do edges on different constraints one constraint at a time.
cband := {
   local connum;
   for ( connum := 1 ; connum <= high_constraint ; connum += 1 ) 
   { if valid_constraint(connum) then
     { set edge inband on_constraint connum;
       makeband;
     }
   };
}

// End band.cmd
// makeband usage:
//   set bandwidth to desired half-width (in surface coordinates)
//   set edge inband to 1 along band center, 0 elsewhere
//   set bandcolor to desired color
//   run makeband
// In making postscript, answer N to gridlines, and y to colors.