[go: up one dir, main page]

File: blend_stuff.c

package info (click to toggle)
circlepack 5.1-3
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k, lenny, sarge
  • size: 2,828 kB
  • ctags: 1,683
  • sloc: ansic: 43,152; makefile: 46
file content (234 lines) | stat: -rw-r--r-- 7,407 bytes parent folder | download | duplicates (3)
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#include "cp_types.h"
#include "cp_proto.h"

/* "Blending" refers to the attachment of one packing to another,
generally with some overlap where a smooth transition in radii
and centers from one pack to the other can be made. (Eg., packing 
'islands' generated with PlugPack or "mending" a flaw.) */

int match(struct p_data *p,struct p_data *q,int v1,int v2,
	  int w1,int w2,double *err,int *err_flag,Mobius *M)
     /* Find mobius M putting pack p in register with q. Both packs
hyp or eucl. Apply 'best' automorphism to line up centers 
of designated vertices: v1 <--> w1, v2 <--> w2. In hyp case,
all centers on unit circle or interior to disc. Return 0 on error. 
Send back err and increment err_flag if there's a mobius error.
(Eventually may want 'best' automorphism for lining up 3 pairs.) */
{
  int err_hit=0;
  double cut;
  complex a1,a2,b1,b2;
  
  *err=0.0;
  if (!p->status || !q->status || p->hes>0
      || v1 < 1 || v2 < 1 || v1 > p->nodecount || v2 > p->nodecount
      || w1 < 1 || w2 < 1 || w1 > q->nodecount || w2 > q->nodecount)
    return 0;
  if (p->hes<0) /* hyperbolic automorphism */
    {
      if (q->hes>=0) return 0;
      a1=p->packR_ptr[v1].center;
      a2=p->packR_ptr[v2].center;
      b1=q->packR_ptr[w1].center;
      b2=q->packR_ptr[w2].center;
      cut=1-m_toler;
      if (cAbs(a1)>cut && cAbs(a2)>cut && cAbs(b1)>cut && cAbs(b2)>cut)
	/* all on unit circle */
	*M=trans_abAB(a1,a2,b1,b2,&err_hit);
      else if 
	(cAbs(a1)<=cut && cAbs(a2)<=cut && cAbs(b1)<=cut && cAbs(b2)<=cut)
	/* all interior */
	*M=auto_abAB(a1,a2,b1,b2,err,&err_hit);
      else
	{
	  sprintf(msgbuf,"match: data not suitable.");
	  emsg();
	  return 0;
	}
      if (err_hit) 
	{
	  (*err_flag)++;
	  return 0;
	}
      return 1;
    }
  if (p->hes>=0) /* eucl automorphism */
    {
      if (q->hes<0) return 0;
      a1=p->packR_ptr[v1].center;
      a2=p->packR_ptr[v2].center;
      b1=q->packR_ptr[w1].center;
      b2=q->packR_ptr[w2].center;
      *M=affine_mob(a1,a2,b1,b2,&err_hit);
      if (err_hit)
	{
	  (*err_flag)++;
	  return 0;
	}
      return 1;
    }
  return 1;
} /* match */

int comb_bdry_antip(struct p_data *p,int *v,int *w)
     /* Given bdry vert v, find bdry vert w in same bdry component
which is combinatorially 'opposite' v. Return 0 on error, eg. bdry
component length < 4; else return distance of v to w along bdry. */
{
  int i,n,vv,count=0;
  struct K_data *pK_ptr;

  pK_ptr=p->packK_ptr;
  vv=*v;
  if (vv<1 || vv>p->nodecount || !pK_ptr[vv].bdry_flag) 
    /* improper vert? use first bdry vert encountered */
    {
      vv=0;
      for (i=1;i<=p->nodecount;i++)
	if (pK_ptr[i].bdry_flag) {vv=i;i=p->nodecount+1;}
      if (!vv) return 0;
      *v=vv;
    }
  if (!(count=bdry_comp_count(p,(*v))) || count<4 )
    return 0;
  
  n=(int)(count/2);
  *w=*v;
  for (i=1;i<=n;i++) (*w)=pK_ptr[(*w)].flower[0];
  return n;
} /* comb_bdry_antip */
	  
int blend(struct p_data *p,struct p_data *q,int bdry_vert,int depth)
     /* Blend pack q centers/radii with pack p centers/radii, putting
result in pack p. (Assume both p, q have been packed.) The vertex_map 
of q will be used to identify circles of q with the corresponding 
circles of p.

bdry_vert is a bdry_vert of q; it and its bdry antipital will be used
for registration purposes, and the resulting mobius is applied to pack
q. Presumably the packing combinatorics are such that they overlap in
a certain combinatorial annulus; 'depth' indicates how many generations 
(counting done in q) are used to smoothly blend the centers of p with 
those of q -- the closer to bdry q, the more heavily the centers of p 
are weighted. Depth 1 means just line up bdry_vert and its antipital;
depth < 0 means allow largest possible depth.

Return number of generations blended (may be less than depth). Return
0 on error. */
{
  int i,hits,v,w,V,W,err_flag=0,*genlist=NULL;
  int *maplist,max_depth,tv,vert_count;
  double err,factor=0.0,ofactor=1.0;
  char *endptr,buf[32];
  Mobius M;
  struct Vertlist *vertlist=NULL,*trace,*bdrylist=NULL,*vtrace;
  struct Edgelist *etrace;
  struct K_data *pK_ptr,*qK_ptr;
  struct R_data *pR_ptr,*qR_ptr;

  pK_ptr=p->packK_ptr;pR_ptr=p->packR_ptr;
  qK_ptr=q->packK_ptr;qR_ptr=q->packR_ptr;
  if (!p->status || !q->status || !q->vertex_map) return 0;
  v=bdry_vert;

  /* find bdry verts to match for registering packings */
  if (!comb_bdry_antip(q,&v,&w) 
      || (V=vertex_translation(q->vertex_map,v))<=0
      || (W=vertex_translation(q->vertex_map,w))<=0)
    return 0; /* if v was not adequate, it was changed in this call */

  /* find and apply Mobius to get q in register with p. */
  if (!match(q,p,v,w,V,W,&err,&err_flag,&M) || err_flag
      || !(bdrylist=Node_link_parse(q,"b",&endptr,&hits,
		    &Vlist,&Elist,&Flist,&region,pathlist,pathlength)) )
    return 0;
  apply_Mobius(q,"a",1,M);
  
  /* get list with generation labels */
  for (i=1;i<=p->nodecount;i++) pK_ptr[i].util_flag=0;
  vtrace=bdrylist;
  while (vtrace)
    {
      pK_ptr[vtrace->v].util_flag=1;
      vtrace=vtrace->next;
    }
  vert_free(&bdrylist);
  if (!(genlist=label_generations(q,depth,&hits,&vert_count)))
    return 0;
  
  /* for efficiency, put vertex_map in vector. */
  maplist=(int *)calloc((size_t)(q->nodecount+1),sizeof(int));
  etrace=q->vertex_map;
  while (etrace)
    {
      maplist[etrace->v]=etrace->w;
      etrace=etrace->next;
    }

  /* what is actual number of generations overlap? (up to 'depth'). */
  max_depth=q->nodecount;
  for (i=1;i<=q->nodecount;i++)
    {
      qK_ptr[i].mark=0;
      if (genlist[i]>0 && genlist[i]<=max_depth && maplist[i]==0)
	/* vert of q in this generation does have corresp. vert in p */
	max_depth=genlist[i]-1;
      else qK_ptr[i].mark=genlist[i]; /* record gen in mark in case
					 we need it later. */
    }
  if (max_depth<1) {free(genlist);return 0;} /* bdry doesn't overlap? */
  if (depth<0) depth=max_depth;
  if (max_depth<depth) depth=max_depth;
  free(genlist);

  /* now set centers of p circles in overlap by going successively 
     through generations in q and weighting their centers with 
     centers already in p. */

  for (i=1;i<=depth;i++)
    {
      sprintf(buf,"{c:m=%d}",i);
      if (!(vertlist=Node_link_parse(q,buf,&endptr,&hits,
		     &Vlist,&Elist,&Flist,&region,pathlist,pathlength)))
	/* should have verts in every generation up to depth */
	{free(maplist);return 0;}
      trace=vertlist;
      if (depth>1) factor=(double)(i-1)/(double)(depth-1);
      ofactor=1.0-factor;
      while (trace)
	{
	  if (!(tv=maplist[trace->v]) || tv>p->nodecount)
	    {
	      vert_free(&vertlist);
	      free(maplist);
	      return 0; /* failed translation */
	    }
	  pR_ptr[tv].center.re=
	    ofactor*pR_ptr[tv].center.re+
	    factor*qR_ptr[trace->v].center.re;
	  pR_ptr[tv].center.im=
	    ofactor*pR_ptr[tv].center.im+
	    factor*qR_ptr[trace->v].center.im;
	  pR_ptr[tv].rad=ofactor*pR_ptr[tv].rad+
	    factor*qR_ptr[trace->v].rad;
	  trace=trace->next;
	} 
      vert_free(&vertlist);
    }

  /* finally, for all the rest of the vertices of q, map their
     centers/radii over to p without change */
  for (i=1;i<=q->nodecount;i++)
    {
      if ((qK_ptr[i].mark>depth || !qK_ptr[i].mark)
	  && (tv=maplist[i]) && tv<=p->nodecount)
	{
	  pR_ptr[tv].center=qR_ptr[i].center;
	  pR_ptr[tv].rad=qR_ptr[i].rad;
	}
    }
  free(maplist);
  return 1;
} /* blend */