[xiph-commits] r10156 - trunk/planarity

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Fri Oct 14 05:22:55 PDT 2005


Author: xiphmont
Date: 2005-10-14 05:22:47 -0700 (Fri, 14 Oct 2005)
New Revision: 10156

Added:
   trunk/planarity/graph_region.c
   trunk/planarity/graph_region.h
Modified:
   trunk/planarity/Makefile
   trunk/planarity/dialog_finish.c
   trunk/planarity/dialog_finish.h
   trunk/planarity/dialog_level_icons.c
   trunk/planarity/gameboard.h
   trunk/planarity/gameboard_draw_edge.c
   trunk/planarity/gameboard_draw_main.c
   trunk/planarity/gameboard_draw_score.c
   trunk/planarity/gameboard_logic.c
   trunk/planarity/gameboard_logic_buttonbar.c
   trunk/planarity/gameboard_logic_fade.c
   trunk/planarity/graph.c
   trunk/planarity/graph.h
   trunk/planarity/graph_arrange.c
   trunk/planarity/graph_arrange.h
   trunk/planarity/graph_generate.c
   trunk/planarity/graph_generate.h
   trunk/planarity/graph_generate_mesh1.c
   trunk/planarity/graph_generate_mesh2.c
   trunk/planarity/graph_score.c
   trunk/planarity/main.c
   trunk/planarity/version.h
Log:
Aside from any remaining bugs, gPlanarity is all done.  No more wibbling around wasting time :-)



Modified: trunk/planarity/Makefile
===================================================================
--- trunk/planarity/Makefile	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/Makefile	2005-10-14 12:22:47 UTC (rev 10156)
@@ -25,7 +25,7 @@
 	gameboard_draw_score.c main.c gameboard_draw_selection.c\
 	timer.c gameboard_draw_vertex.c levelstate.c dialog_level.c\
 	dialog_level_icons.c gameboard_draw_text.c random.c graph_generate_data.c\
-	gameboard_logic_fade.c graph_generate_mesh2.c
+	gameboard_logic_fade.c graph_generate_mesh2.c graph_region.c
 OBJ  = dialog_finish.o gameboard_logic.o dialog_pause.o gameboard_logic_button.o\
 	gameboard.o gameboard_logic_buttonbar.o gameboard_draw_box.o\
 	gameboard_logic_mouse.o gameboard_draw_button.o gameboard_logic_push.o\
@@ -35,7 +35,7 @@
 	gameboard_draw_score.o main.o gameboard_draw_selection.o\
 	timer.o gameboard_draw_vertex.o levelstate.o dialog_level.o\
 	dialog_level_icons.o gameboard_draw_text.o random.o graph_generate_data.o\
-	gameboard_logic_fade.o graph_generate_mesh2.o
+	gameboard_logic_fade.o graph_generate_mesh2.o graph_region.o
 CAIROVER =  >= 1.0.0
 GTKVER   =  >= 2.7.2
 GCF  = `pkg-config --static --cflags "gtk+-2.0 $(GTKVER) cairo $(CAIROVER)"`
@@ -68,13 +68,16 @@
 	$(STRIP) $(TARGET)
 
 static:    
+	pkg-config --cflags "gtk+-2.0 $(GTKVER) cairo $(CAIROVER)" 1>/dev/null
 	$(MAKE) static-target CFLAGS="-O2 -ffast-math $(GCF) $(ADD_DEF) "	
 	$(STRIP) $(TARGET)
 
 debug:
+	pkg-config --cflags "gtk+-2.0 $(GTKVER) cairo $(CAIROVER)" 1>/dev/null
 	$(MAKE) target CFLAGS="-g -Wall -W -Wno-unused-parameter -D__NO_MATH_INLINES $(GCF) $(ADD_DEF)"
 
 profile:
+	pkg-config --cflags "gtk+-2.0 $(GTKVER) cairo $(CAIROVER)" 1>/dev/null
 	$(MAKE) target CFLAGS="-pg -g -O2 -ffast-math $(GCF) $(ADD_DEF)" LIBS="$(LIBS) -lgprof-helper "
 
 clean:

Modified: trunk/planarity/dialog_finish.c
===================================================================
--- trunk/planarity/dialog_finish.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/dialog_finish.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -168,12 +168,12 @@
     snprintf(buffer,160,"Base score: %d points",graphscore_get_raw_score(&g->g));
     render_bordertext_centered(c,buffer, w/2,y);y+=24;
 
-    if(graphscore_get_multiplier(&g->g)>1){
+    if(graphscore_get_multiplier_percent(&g->g)>100){
       cairo_save(c);
       set_font(c,16,16,0,1);
       cairo_set_source_rgba (c, HIGH_COLOR);
       
-      snprintf(buffer,160,"Objective Exceeded! x%d",graphscore_get_multiplier(&g->g));
+      snprintf(buffer,160,"Objective Exceeded! %d%%",graphscore_get_multiplier_percent(&g->g));
       render_bordertext_centered(c,buffer, w/2,y);y+=24;
       cairo_restore(c);
     }

Modified: trunk/planarity/dialog_finish.h
===================================================================
--- trunk/planarity/dialog_finish.h	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/dialog_finish.h	2005-10-14 12:22:47 UTC (rev 10156)
@@ -26,7 +26,7 @@
 
 #define FINISH_BUTTON_BORDER 35
 #define FINISH_BUTTON_Y 25
-#define FINISHBOX_WIDTH 250
+#define FINISHBOX_WIDTH 270
 #define FINISHBOX_HEIGHT 330
 
 extern void finish_level_dialog(Gameboard *g);

Modified: trunk/planarity/dialog_level_icons.c
===================================================================
--- trunk/planarity/dialog_level_icons.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/dialog_level_icons.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -135,6 +135,7 @@
     if(g->b.buttons_ready){
       if(g->button_timer!=0)
 	g_source_remove(g->button_timer);
+      g->button_callback=0;
       g->button_timer = g_timeout_add(BUTTON_ANIM_INTERVAL, animate_button_frame, (gpointer)g);
     }
   }
@@ -153,6 +154,7 @@
     if(g->b.buttons_ready){
       if(g->button_timer!=0)
 	g_source_remove(g->button_timer);
+      g->button_callback = 0;
       g->button_timer = g_timeout_add(BUTTON_ANIM_INTERVAL, animate_button_frame, (gpointer)g);
     } 
   }
@@ -173,6 +175,7 @@
     dialog_level_oneicon_init(g,i-2,g->d.level_icons+i);
 
   g->d.center_x = 0;
+  g->d.center_done=1;
   g->d.level_lit = 2;
   g->d.reset_deployed = 0;
 
@@ -212,12 +215,12 @@
 	if( iy+ih < ey ) continue;
 	if( iy > ey2 ) continue;
 
-	if(l->icon){
+	if(l->icon && cairo_surface_status(l->icon)==CAIRO_STATUS_SUCCESS){
 	  cairo_set_source_surface(c,l->icon,ix,iy);
 	  cairo_paint_with_alpha(c,l->alpha);
 	}
 
-	if(g->d.center_x==0){
+	if(g->d.center_x==0 && g->d.center_done){
 	  if(i==2){
 	    cairo_set_source_rgba (c, B_COLOR);
 	    borderbox_path(c,ix+1.5,iy+1.5,iw-3,ih-3);
@@ -233,7 +236,7 @@
     }
 
     // render level related text
-    if(g->d.center_x == 0 && c){
+    if(g->d.center_x == 0 && g->d.center_done && c){
       char buffer[160];
 
       // above text
@@ -291,6 +294,7 @@
   int i;
 
   if(g->d.center_x == 0){
+    g->d.center_done=1;
     g_source_remove(g->d.icon_timer);
     g->d.icon_timer=0;
 
@@ -301,6 +305,7 @@
     return 0;
   }
 
+  g->d.center_done=0;
   for(i=0;i<5;i++)
     if(g->d.level_icons[i].alpha)
       invalidate_icon(g, g->d.level_icons+i);
@@ -372,9 +377,9 @@
   if(g->d.level_lit == 1){
     if(levelstate_prev()){
 
-    if(!levelstate_in_progress())
-      undeploy_reset_button(g);
-
+      if(!levelstate_in_progress())
+	undeploy_reset_button(g);
+      
       if(g->d.level_icons[4].icon)
 	cairo_surface_destroy(g->d.level_icons[4].icon);
       for(i=4;i>=1;i--){
@@ -384,7 +389,7 @@
       g->d.level_icons[0].icon=0;
       dialog_level_oneicon_init(g,-2,g->d.level_icons);
       
-      if(g->d.center_x==0)expose_full(g); // only needed to 'undraw' the text
+      if(g->d.center_x==0 && g->d.center_done)expose_full(g); // only needed to 'undraw' the text
 
       g->d.center_x = g->d.level_icons[1].x - g->d.level_icons[2].x;
     }
@@ -405,7 +410,7 @@
       g->d.level_icons[4].icon=0;
       dialog_level_oneicon_init(g,2,g->d.level_icons+4);
       
-      if(g->d.center_x==0)expose_full(g); // only needed to 'undraw' the text
+      if(g->d.center_x==0 && g->d.center_done)expose_full(g); // only needed to 'undraw' the text
 
       g->d.center_x = g->d.level_icons[3].x - g->d.level_icons[2].x;
 

Modified: trunk/planarity/gameboard.h
===================================================================
--- trunk/planarity/gameboard.h	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/gameboard.h	2005-10-14 12:22:47 UTC (rev 10156)
@@ -46,6 +46,7 @@
 #define INTERSECTION_LINE_WIDTH 2
 
 #define RESET_DELTA 2
+#define SCALE_DELTA 8
 
 #define B_LINE 1
 #define B_BORDER 6.5
@@ -143,6 +144,7 @@
 
   dialog_level_oneicon level_icons[5];
   int center_x;
+  int center_done;
   int level_lit;
   int reset_deployed;
   
@@ -179,6 +181,7 @@
   int delayed_background;
   int first_expose;
   int hide_lines;
+  int realtime_background;
   int show_intersections;
   int finish_dialog_active;
   int about_dialog_active;
@@ -330,4 +333,4 @@
 extern void fade_cancel(Gameboard *g);
 extern void fade_attached(Gameboard *g,vertex *v);
 extern void fade_grabbed(Gameboard *g);
-
+extern void fade_marked(Gameboard *g);

Modified: trunk/planarity/gameboard_draw_edge.c
===================================================================
--- trunk/planarity/gameboard_draw_edge.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/gameboard_draw_edge.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -80,8 +80,6 @@
   }
 }
 
-
-
 /* invalidate edge region for efficient expose *******************/
 
 void invalidate_edges(GtkWidget *widget, vertex *v, int offx, int offy){

Modified: trunk/planarity/gameboard_draw_main.c
===================================================================
--- trunk/planarity/gameboard_draw_main.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/gameboard_draw_main.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -113,6 +113,8 @@
 	    draw_vertex(c,v,g->vertex_grabbed);      
 	  } else if( v->selected ){
 	    draw_vertex(c,v,g->vertex_sel);
+	    if(v->fading)
+	      draw_vertex_with_alpha(c,v,g->vertex_ghost,alpha);
 	  } else if ( v == g->lit_vertex){
 	    draw_vertex(c,v,g->vertex_lit);
 	  } else if (v->attached_to_grabbed){
@@ -138,13 +140,51 @@
 
   cairo_set_source_rgb(c,1,1,1);
   cairo_paint(c);
-    
+  
   if(!g->hide_lines){
     setup_background_edge(c);
     while(e){
-      if(e->active){
+      if(e->active)
 	draw_edge(c,e);
+      e=e->next;
+    }
+    finish_edge(c);
+  }
+}
+
+static void draw_background_realpart(Gameboard *g,cairo_t *c,
+				     int x, int y, int w, int h){
+  edge *e=g->g.edges;
+  int x2 = x+w-1+E_LINE;
+  int y2 = y+h-1+E_LINE;
+  x-=E_LINE;
+  y-=E_LINE;
+
+  cairo_set_source_rgb(c,1,1,1);
+  cairo_paint(c);
+  
+  if(!g->hide_lines){
+    setup_background_edge(c);
+    while(e){
+      int ex1 = e->A->x;
+      int ex2 = e->B->x;
+      int ey1 = e->A->y;
+      int ey2 = e->B->y;
+
+      if(ex1<ex2){
+	if(x>ex2 || x2<ex1){e=e->next;continue;}
+      }else{
+	if(x>ex1 || x2<ex2){e=e->next;continue;}
       }
+
+      if(ey1<ey2){
+	if(y>ey2 || y2<ey1){e=e->next;continue;}
+      }else{
+	if(y>ey1 || y2<ey2){e=e->next;continue;}
+      }
+
+      draw_edge(c,e);
+
       e=e->next;
     }
     finish_edge(c);
@@ -268,16 +308,18 @@
    operations where expose combining causes huge, slow in-server alpha
    blends that are undesirable) */
 void gameboard_draw(Gameboard *g, int x, int y, int w, int h){
-  
+  cairo_t *c = cairo_create(g->foreground);
   if (w==0 || h==0) return;
-  
-  cairo_t *c = cairo_create(g->foreground);
-  
-  // copy background to foreground draw buffer
-  cairo_set_source_surface(c,g->background,0,0);
-  cairo_rectangle(c,x,y,w,h);
-  cairo_fill(c);
 
+  if(g->realtime_background){
+    draw_background_realpart(g,c,x,y,w,h);
+  }else{
+    // copy background to foreground draw buffer
+    cairo_set_source_surface(c,g->background,0,0);
+    cairo_rectangle(c,x,y,w,h);
+    cairo_fill(c);
+  }
+
   if(!g->pushed_curtain){
     draw_foreground(g,c,x,y,w,h);
     
@@ -324,7 +366,7 @@
   
   cairo_surface_t *s = cairo_image_surface_create_from_png(name);
 
-  if(s==NULL)
+  if(s==NULL || cairo_surface_status(s)!=CAIRO_STATUS_SUCCESS)
     fprintf(stderr,"ERROR:  Could not load board icon \"%s\"\n",
 	    name);
 

Modified: trunk/planarity/gameboard_draw_score.c
===================================================================
--- trunk/planarity/gameboard_draw_score.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/gameboard_draw_score.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -66,7 +66,7 @@
 
   snprintf(level_string,160,"Level %d: %s",get_level_num()+1,get_level_desc());
   snprintf(score_string,160,"Score: %d",graphscore_get_raw_score(&g->g));
-  snprintf(mult_string,160,"x%d",graphscore_get_multiplier(&g->g));
+  snprintf(mult_string,160,"%d%%",graphscore_get_multiplier_percent(&g->g));
   snprintf(int_string,160,"Intersections: %ld",g->g.active_intersections);
   snprintf(obj_string,160,"Objective: %s",graphscore_objective_string(&g->g));
 
@@ -83,7 +83,7 @@
   cairo_show_text (c, int_string);  
   cairo_move_to (c, 15, ty2);
   cairo_show_text (c, score_string);  
-  if(graphscore_get_multiplier(&g->g)>1){
+  if(graphscore_get_multiplier_percent(&g->g)>100){
     cairo_save(c);
     cairo_set_source_rgba (c, HIGH_COLOR);
     cairo_move_to (c, 15 + extentsS.width+10, ty2);

Modified: trunk/planarity/gameboard_logic.c
===================================================================
--- trunk/planarity/gameboard_logic.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/gameboard_logic.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -72,11 +72,109 @@
   reenter_game(g);
 }
 
+static void animate_verticies(Gameboard *g, 
+			      int *x_target,
+			      int *y_target,
+			      float *delta){
+  int flag=1,count=0;
+  vertex *v=g->g.verticies;
+  float *tx=alloca(g->g.vertex_num * sizeof(*tx));
+  float *ty=alloca(g->g.vertex_num * sizeof(*ty));
+
+  // hide intersections now; deactivating the verticies below will hide them anyway
+  g->show_intersections = 0;
+  g->realtime_background = 1;
+  update_full(g);
+
+  // deactivate all the verticies so they can be moved en-masse
+  // without graph metadata updates at each move
+  v=g->g.verticies;
+  while(v){
+    deactivate_vertex(&g->g,v);
+    tx[count]=v->x;
+    ty[count++]=v->y;
+    v=v->next;
+  }
+
+  // animate
+  while(flag){
+    count=0;
+    flag=0;
+    
+    v=g->g.verticies;
+    while(v){
+      if(v->x!=x_target[count] || v->y!=y_target[count]){
+	
+	float xd = x_target[count] - tx[count];
+	float yd = y_target[count] - ty[count];
+	float m = hypot(xd,yd);
+
+	tx[count]+= xd/m*delta[count];
+	ty[count]+= yd/m*delta[count];
+	
+	invalidate_vertex(g,v);
+	invalidate_edges(GTK_WIDGET(g),v,0,0);
+
+	v->x = rint(tx[count]);
+	v->y = rint(ty[count]);
+
+	if( (v->x > x_target[count] && xd > 0) ||
+	    (v->x < x_target[count] && xd < 0) ||
+	    (v->y > y_target[count] && yd > 0) ||
+	    (v->y < y_target[count] && yd < 0) ){
+	  v->x = x_target[count];
+	  v->y = y_target[count];
+	}else
+	  flag=1;
+
+	invalidate_vertex(g,v);
+	invalidate_edges(GTK_WIDGET(g),v,0,0);
+
+      }	    
+      count++;
+      v=v->next;
+    }
+
+    gdk_window_process_all_updates();
+    gdk_flush();
+    
+  }
+
+  // reactivate all the verticies 
+  activate_verticies(&g->g);
+
+  // update the score 
+  update_score(g);
+
+  // it's a reset; show lines is default. This also has the side
+  // effect of forcing a full board redraw and expose
+  g->realtime_background=0;
+  update_full(g);
+
+  // possible
+  if(g->g.active_intersections <= g->g.objective){
+    deploy_check(g);
+  }else{
+    undeploy_check(g);
+  }
+
+}
+
+
 static void scale(Gameboard *g,double scale){
   int x=g->g.width/2;
   int y=g->g.height/2;
   int sel = num_selected_verticies(&g->g);
   vertex *v;
+  int *tx=alloca(g->g.vertex_num * sizeof(*tx));
+  int *ty=alloca(g->g.vertex_num * sizeof(*ty));
+  float *tm=alloca(g->g.vertex_num * sizeof(*ty));
+  int i=0;
+  int minx=0;
+  int maxx=g->g.width-1;
+  int miny=0;
+  int maxy=g->g.height-1;
+  int okflag=0;
 
   // if selected, expand from center of selected mass
   if(sel){
@@ -95,61 +193,63 @@
     y = yac / sel;
   }
 
-  v=g->g.verticies;
-  while(v){
-  
-    if(!sel || v->selected){
-      float nx = (v->x - x)*scale+x;
-      float ny = (v->y - y)*scale+y;
+  while(!okflag){
+    okflag=1;
+    i=0;
+    v=g->g.verticies;
+    while(v){
+      
+      if(!sel || v->selected){
+	float nx = rint((v->x - x)*scale+x);
+	float ny = rint((v->y - y)*scale+y);
+	float m = hypot(nx - v->x,ny-v->y)/5;
+	
+	if(nx<minx){
+	  scale = (float)(minx-x) / (v->x-x);
+	  okflag=0;
+	}
 
-      if(nx<0 || nx>=g->g.width ||
-	 ny<0 || ny>=g->g.height){
+	if(nx>maxx){
+	  scale = (float)(maxx-x) / (v->x - x);
+	  okflag=0;
+	}
 
-	float mag = hypot(nx-x,ny-y);
-	if(mag){
-	  float ang = acos((nx-x) / mag);
-	  if(ny-y>0) ang = 2*M_PI-ang;
+	if(ny<miny){
+	  scale = (float)(miny-y) / (v->y-y);
+	  okflag=0;
+	}
 
-	  if(nx<0){
-	    mag *= -x/(nx-x);
-	    nx = cos(ang)*mag+x;
-	    ny = -sin(ang)*mag+y;
-	  }
-
-	  if(nx>=g->g.width){
-	    mag *= (g->g.width-x-1)/(nx-x);
-	    nx = cos(ang)*mag+x;
-	    ny = -sin(ang)*mag+y;
-	  }
-
-	  if(ny<0){
-	    mag *= -y/(ny-y);
-	    nx = cos(ang)*mag+x;
-	    ny = -sin(ang)*mag+y;
-	  }
-
-	  if(ny>=g->g.height){
-	    mag *= (g->g.height-y-1)/(ny-y);
-	    nx = cos(ang)*mag+x;
-	    ny = -sin(ang)*mag+y;
-	  }
+	if(ny>maxy){
+	  scale = (float)(maxy-y) / (v->y - y);
+	  okflag=0;
 	}
+	if(m<1)m=1;
+      
+	tx[i] = rint(nx);
+	ty[i] = rint(ny);
+	tm[i++] = m;
+      }else{
+	tx[i] = v->x;
+	ty[i] = v->y;
+	tm[i++] = 0;
       }
-
-      deactivate_vertex(&g->g,v);
-      v->x = rint(nx);
-      v->y = rint(ny);
+      v=v->next;
     }
-    v=v->next;
   }
   
-  v=g->g.verticies;
-  while(v){
-    activate_vertex(&g->g,v);
-    v=v->next;
+  if(scale>=.99999 && scale<=1.00001){
+    ungrab_verticies(&g->g);
+    v=g->g.verticies;
+    while(v){
+      if(v->x<2 || v->x>=g->g.width-3)v->grabbed=1;
+      if(v->y<2 || v->y>=g->g.height-3)v->grabbed=1;
+      v=v->next;
+    }
+    fade_marked(g);
+    ungrab_verticies(&g->g);
+  }else{
+    animate_verticies(g,tx,ty,tm);
   }
-
-  update_full(g);
 }
 
 static void gtk_main_quit_wrapper(Gameboard *g){
@@ -231,76 +331,20 @@
 }
 
 void reset_action(Gameboard *g){
-  int flag=1;
   vertex *v=g->g.verticies;
+  int *target_x = alloca(g->g.vertex_num * sizeof(*target_x));
+  int *target_y = alloca(g->g.vertex_num * sizeof(*target_y));
+  float *target_m = alloca(g->g.vertex_num * sizeof(*target_m));
+  int i=0;
 
-  // hide intersections now; deactivating the verticies below will hide them anyway
-  g->show_intersections = 0;
-  expose_full(g);
-  gdk_window_process_all_updates();
-  gdk_flush();
-
-  // deactivate all the verticies so they can be moved en-masse
-  // without graph metadata updates at each move
   while(v){
-    deactivate_vertex(&g->g,v);
+    target_x[i]=v->orig_x;
+    target_y[i]=v->orig_y;
+    target_m[i++]=RESET_DELTA;
     v=v->next;
   }
 
-  // animate
-  while(flag){
-    flag=0;
-
-    v=g->g.verticies;
-    while(v){
-      int bxd = (g->g.width - g->g.orig_width) >>1;
-      int byd = (g->g.height - g->g.orig_height) >>1;
-      int vox = v->orig_x + bxd;
-      int voy = v->orig_y + byd;
-
-      if(v->x != vox || v->y != voy){
-	flag=1;
-      
-	invalidate_vertex(g,v);
-	if(v->x<vox){
-	  v->x+=RESET_DELTA;
-	  if(v->x>vox)v->x=vox;
-	}else{
-	  v->x-=RESET_DELTA;
-	  if(v->x<vox)v->x=vox;
-	}
-	if(v->y<voy){
-	  v->y+=RESET_DELTA;
-	  if(v->y>voy)v->y=voy;
-	}else{
-	  v->y-=RESET_DELTA;
-	  if(v->y<voy)v->y=voy;
-	}
-	invalidate_vertex(g,v);
-      }
-      v=v->next;
-    }
-    gdk_window_process_all_updates();
-    gdk_flush();
-    
-  }
-
-  // reactivate all the verticies 
-  activate_verticies(&g->g);
-
-  // update the score 
-  update_score(g);
-
-  // it's a reset; show lines is default. This also has the side
-  // effect of forcing a full board redraw and expose
-  set_hide_lines(g,0);
-
-  // hey, the board could ahve come pre-solved
-  if(g->g.active_intersections <= g->g.objective){
-    deploy_check(g);
-  }else{
-    undeploy_check(g);
-  }
+  animate_verticies(g,target_x,target_y,target_m);
   
   // reset timer
   set_timer(0);

Modified: trunk/planarity/gameboard_logic_buttonbar.c
===================================================================
--- trunk/planarity/gameboard_logic_buttonbar.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/gameboard_logic_buttonbar.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -151,6 +151,7 @@
 
     if(g->button_timer!=0)
       g_source_remove(g->button_timer);
+    g->button_callback=0;
     g->button_timer = g_timeout_add(BUTTON_ANIM_INTERVAL, animate_button_frame, (gpointer)g);
     g->checkbutton_deployed=1;
   }
@@ -169,6 +170,7 @@
 
     if(g->button_timer!=0)
       g_source_remove(g->button_timer);
+    g->button_callback=0;
     g->button_timer = g_timeout_add(BUTTON_ANIM_INTERVAL, animate_button_frame, (gpointer)g);
     g->checkbutton_deployed=0;
   }

Modified: trunk/planarity/gameboard_logic_fade.c
===================================================================
--- trunk/planarity/gameboard_logic_fade.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/gameboard_logic_fade.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -152,3 +152,21 @@
   f->fade_timer = g_timeout_add(FADE_ANIM_INTERVAL, animate_fade, (gpointer)g);
 }
 
+void fade_marked(Gameboard *g){
+  fade_state *f = &g->fade;
+  vertex *v = g->g.verticies;
+
+  /* If a fade is already in progress, cancel it */
+  fade_cancel(g);
+
+  while(v){
+    if(v->grabbed)
+      fade_add_vertex(f,v);
+    v=v->next;
+  }
+
+  f->count = FADE_FRAMES;
+
+  f->fade_timer = g_timeout_add(FADE_ANIM_INTERVAL, animate_fade, (gpointer)g);
+}
+

Modified: trunk/planarity/graph.c
===================================================================
--- trunk/planarity/graph.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/graph.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -232,51 +232,60 @@
   g->num_edges_active=0;
 }
 
-int intersects(vertex *L1, vertex *L2, vertex *M1, vertex *M2, double *xo, double *yo){
+int intersectsV(vertex *L1, vertex *L2, vertex *M1, vertex *M2, double *xo, double *yo){
+  // edges that share a vertex don't intersect by definition
+  if(L1==M1) return 0;
+  if(L1==M2) return 0;
+  if(L2==M1) return 0;
+  if(L2==M2) return 0;
+
+  return intersects(L1->x,L1->y,L2->x,L2->y,M1->x,M1->y,M2->x,M2->y,xo,yo);
+}
+
+int intersects(int L1x, int L1y,
+		int L2x, int L2y,
+		int M1x, int M1y,
+		int M2x, int M2y,
+		double *xo, double *yo){
+
   /* y = ax + b */
   float La=0;
   float Lb=0;
   float Ma=0;
   float Mb=0;
 
-  // but first, edges that share a vertex don't intersect by definition
-  if(L1==M1) return 0;
-  if(L1==M2) return 0;
-  if(L2==M1) return 0;
-  if(L2==M2) return 0;
-
-  if(L1->x != L2->x){
-    La = (float)(L2->y - L1->y) / (L2->x - L1->x);
-    Lb = (L1->y - L1->x * La);
+  if(L1x != L2x){
+    La = (float)(L2y - L1y) / (L2x - L1x);
+    Lb = (L1y - L1x * La);
   }
   
-  if(M1->x != M2->x){
-    Ma = (float)(M2->y - M1->y) / (M2->x - M1->x);
-    Mb = (M1->y - M1->x * Ma);
+  if(M1x != M2x){
+    Ma = (float)(M2y - M1y) / (M2x - M1x);
+    Mb = (M1y - M1x * Ma);
   }
   
-  if(L1->x == L2->x){
+  if(L1x == L2x){
     // L is vertical line
 
-    if(M1->x == M2->x){
+    if(M1x == M2x){
       // M is also a vertical line
 
-      if(L1->x == M1->x){
+      if(L1x == M1x){
 	// L and M vertical on same x, overlap?
-	if(M1->y > L1->y && 
-	   M1->y > L2->y &&
-	   M2->y > L1->y &&
-	   M2->y > L2->y) return 0;
-	if(M1->y < L1->y && 
-	   M1->y < L2->y &&
-	   M2->y < L1->y &&
-	   M2->y < L2->y) return 0;
+	if(M1y > L1y && 
+	   M1y > L2y &&
+	   M2y > L1y &&
+	   M2y > L2y) return 0;
+	if(M1y < L1y && 
+	   M1y < L2y &&
+	   M2y < L1y &&
+	   M2y < L2y) return 0;
 
 	{
-	  double y1=max( min(M1->y,M2->y), min(L1->y, L2->y));
-	  double y2=min( max(M1->y,M2->y), max(L1->y, L2->y));
+	  double y1=max( min(M1y,M2y), min(L1y, L2y));
+	  double y2=min( max(M1y,M2y), max(L1y, L2y));
 
-	  *xo = M1->x;
+	  *xo = M1x;
 	  *yo = (y1+y2)*.5;
 
 	}
@@ -289,39 +298,39 @@
       // L vertical, M not vertical
       
       // needed if L is vertical and M is horizontal
-      if(L1->x < M1->x && L1->x < M2->x) return 0;
-      if(L1->x > M1->x && L1->x > M2->x) return 0;
+      if(L1x < M1x && L1x < M2x) return 0;
+      if(L1x > M1x && L1x > M2x) return 0;
 
       {
-	float y = Ma*L1->x + Mb;
+	float y = Ma*L1x + Mb;
 	
-	if(y < L1->y && y < L2->y) return 0;
-	if(y > L1->y && y > L2->y) return 0;
-	if(y < M1->y && y < M2->y) return 0;
-	if(y > M1->y && y > M2->y) return 0;
+	if(y < L1y && y < L2y) return 0;
+	if(y > L1y && y > L2y) return 0;
+	if(y < M1y && y < M2y) return 0;
+	if(y > M1y && y > M2y) return 0;
 	
-	*xo = L1->x;
+	*xo = L1x;
 	*yo=y;
       }
     }
   }else{
 
-    if(M1->x == M2->x){
+    if(M1x == M2x){
       // M vertical, L not vertical
 
       // needed if L is vertical and M is horizontal
-      if(M1->x < L1->x && M1->x < L2->x) return 0;
-      if(M1->x > L1->x && M1->x > L2->x) return 0;
+      if(M1x < L1x && M1x < L2x) return 0;
+      if(M1x > L1x && M1x > L2x) return 0;
 
       {
-	float y = La*M1->x + Lb;
+	float y = La*M1x + Lb;
 	
-	if(y < L1->y && y < L2->y) return 0;
-	if(y > L1->y && y > L2->y) return 0;
-	if(y < M1->y && y < M2->y) return 0;
-	if(y > M1->y && y > M2->y) return 0;
+	if(y < L1y && y < L2y) return 0;
+	if(y > L1y && y > L2y) return 0;
+	if(y < M1y && y < M2y) return 0;
+	if(y > M1y && y > M2y) return 0;
 	
-	*xo = M1->x;
+	*xo = M1x;
 	*yo=y;
       }
     }else{
@@ -332,20 +341,20 @@
 	if(Mb != Lb) return 0; 
 	
 	// two segments on same line...
-	if(M1->x > L1->x && 
-	   M1->x > L2->x &&
-	   M2->x > L1->x &&
-	   M2->x > L2->x) return 0;
-	if(M1->x < L1->x && 
-	   M1->x < L2->x &&
-	   M2->x < L1->x &&
-	   M2->x < L2->x) return 0;
+	if(M1x > L1x && 
+	   M1x > L2x &&
+	   M2x > L1x &&
+	   M2x > L2x) return 0;
+	if(M1x < L1x && 
+	   M1x < L2x &&
+	   M2x < L1x &&
+	   M2x < L2x) return 0;
 	
 	{
-	  double x1=max( min(M1->x,M2->x), min(L1->x, L2->x));
-	  double x2=min( max(M1->x,M2->x), max(L1->x, L2->x));
-	  double y1=max( min(M1->y,M2->y), min(L1->y, L2->y));
-	  double y2=min( max(M1->y,M2->y), max(L1->y, L2->y));
+	  double x1=max( min(M1x,M2x), min(L1x, L2x));
+	  double x2=min( max(M1x,M2x), max(L1x, L2x));
+	  double y1=max( min(M1y,M2y), min(L1y, L2y));
+	  double y2=min( max(M1y,M2y), max(L1y, L2y));
 	  
 	  *xo = (x1+x2)*.5;
 	  *yo = (y1+y2)*.5;
@@ -357,10 +366,10 @@
 	// finally typical case: L and M have different non-infinite slopes
 	float x = (Mb-Lb) / (La - Ma);
 	
-	if(x < L1->x && x < L2->x) return 0;
-	if(x > L1->x && x > L2->x) return 0;
-	if(x < M1->x && x < M2->x) return 0;
-	if(x > M1->x && x > M2->x) return 0;
+	if(x < L1x && x < L2x) return 0;
+	if(x > L1x && x > L2x) return 0;
+	if(x < M1x && x < M2x) return 0;
+	if(x > M1x && x > M2x) return 0;
 	
 	*xo = x;
 	*yo = La*x + Lb;
@@ -378,7 +387,7 @@
     while(test){
       if(test != e && test->active){
 	double x,y;
-	if(intersects(e->A,e->B,test->A,test->B,&x,&y)){
+	if(intersectsV(e->A,e->B,test->A,test->B,&x,&y)){
 	  add_paired_intersection(e,test,x,y);
 	  g->active_intersections++;
 

Modified: trunk/planarity/graph.h
===================================================================
--- trunk/planarity/graph.h	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/graph.h	2005-10-14 12:22:47 UTC (rev 10156)
@@ -110,9 +110,11 @@
 extern edge *new_edge(vertex *A, vertex *B);
 extern void release_edge_list(edge_list *el);
 extern void insert_edge(graph *g, edge *e);
-extern int intersects(vertex *L1, vertex *L2, vertex *M1, vertex *M2, 
+extern int intersectsV(vertex *L1, vertex *L2, vertex *M1, vertex *M2, 
+		       double *xo, double *yo);
+extern int intersects(int L1x, int L1y, int L2x, int L2y,
+		      int M1x, int M1y, int M2x, int M2y,
 		      double *xo, double *yo);
-
 extern void move_vertex(graph *g, vertex *v, int x, int y);
 extern void grab_vertex(graph *g, vertex *v);
 extern void grab_selected(graph *g);
@@ -141,8 +143,8 @@
 extern int graph_read(graph *g, FILE *f);
 extern void graph_release(graph *g);
 
-extern int graphscore_get_score(graph *g);
-extern int graphscore_get_raw_score(graph *g);
-extern int graphscore_get_multiplier(graph *g);
-extern int graphscore_get_bonus(graph *g);
+extern int   graphscore_get_score(graph *g);
+extern int   graphscore_get_raw_score(graph *g);
+extern int   graphscore_get_multiplier_percent(graph *g);
+extern int   graphscore_get_bonus(graph *g);
 extern char *graphscore_objective_string(graph *g);

Modified: trunk/planarity/graph_arrange.c
===================================================================
--- trunk/planarity/graph_arrange.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/graph_arrange.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -30,6 +30,7 @@
 #include "random.h"
 #include "gameboard.h"
 #include "graph_arrange.h"
+#include "graph_region.h"
 
 void arrange_verticies_circle(graph *g, float off1, float off2){
   vertex *v = g->verticies;
@@ -203,35 +204,245 @@
   }
 }
 
-void arrange_verticies_cloud(graph *g){
-  vertex *v = g->verticies;
-  int n = g->vertex_num;
+void arrange_region_star(graph *g){
+  region_init();
+  region_new_area(400,45,1);
+  region_line_to(340,232);
+  region_line_to(143,232);
+  region_line_to(303,347);
+  region_line_to(241,533);
+  region_line_to(400,417);
+  region_line_to(559,533);
+  region_line_to(497,347);
+  region_line_to(657,232);
+  region_line_to(460,232);
+  region_close_line();
+  region_layout(g);
+}
+
+void arrange_region_rainbow(graph *g){
+  region_init();
+  region_new_area(40,500,2);
+  region_arc_to(760,500,-M_PI);
+  region_line_to(660,500);
+  region_arc_to(200,500,M_PI);
+  region_close_line();
+  region_layout(g);
+}
+
+void arrange_region_dashed_circle(graph *g){
   int bw=g->orig_width;
   int bh=g->orig_height;
-  int radiusx=min(bw,bh)*.55;
-  int radiusy=min(bw,bh)*.40;
+  int radius=min(bw,bh)*.45;
   int i;
-  
-  // first half form an outer perimiter
 
-  for(i=0;i<n/2;i++){
-    v->x = rint( radiusx * cos( i*M_PI*4./n) + (bw>>1));
-    v->y = rint( radiusy * sin( i*M_PI*4./n) + (bh>>1));
-    v=v->next;
+  region_init();
+
+  for(i=0;i<20;i+=2){
+    float phi0=(M_PI*2.f/20*(i-.5));
+    float phi1=(M_PI*2.f/20*(i+.5));
+    int x1=  cos(phi0)*radius+bw/2;
+    int y1= -sin(phi0)*radius+bh/2;
+    int x2=  cos(phi1)*radius+bw/2;
+    int y2= -sin(phi1)*radius+bh/2;
+    region_new_area(x1,y1,3);
+    region_arc_to(x2,y2,M_PI/10);
   }
+  region_layout(g);
+}
 
-  // second third form an inner perimiter
+void arrange_region_bifur(graph *g){
+  int bw=g->orig_width;
+  int bh=g->orig_height;
 
-  for(;i<n/2+n/3;i++){
-    v->x = rint( radiusx * .7 * cos( i*M_PI*6./n) + (bw>>1));
-    v->y = rint( radiusy * .7 * sin( i*M_PI*6./n) + (bh>>1));
-    v=v->next;
+  region_init();
+  region_new_area(21,60,2);
+  region_line_to(bw/2-130,60);
+  region_arc_to(bw/2+130,60,-M_PI*.25);
+  region_line_to(bw-21,60);
+
+  region_new_area(21,bh-60,1);
+  region_line_to(bw/2-130,bh-60);
+  region_arc_to(bw/2+130,bh-60,M_PI*.25);
+  region_line_to(bw-21,bh-60);
+
+  region_layout(g);
+
+}
+
+void arrange_region_dairyqueen(graph *g){
+  int bw=g->orig_width;
+  int bh=g->orig_height;
+  int radius=min(bw,bh)*.45;
+
+  float phi0=(M_PI/2 + M_PI*2.f/8);
+  float phi1=(M_PI/2 - M_PI*2.f/8);
+
+  int x1=  cos(phi0)*radius+bw/2;
+  int x2=  cos(phi1)*radius+bw/2;
+
+  int y1= -sin(phi0)*radius+bh/2;
+  int y2=  sin(phi0)*radius+bh/2;
+
+  region_init();
+
+  region_new_area(x1,y1,2);
+  region_arc_to(x2,y1,-M_PI/2);
+  region_line_to(750,bh/2);
+  region_line_to(x2,y2);
+  region_arc_to(x1,y2,-M_PI/2);
+  region_line_to(50,bh/2);
+  region_close_line();
+
+  region_layout(g);
+}
+
+void arrange_region_cloud(graph *g){
+  int bw=g->orig_width;
+  int bh=g->orig_height;
+  int radius=min(bw,bh)*.45-20;
+  int i=0;
+  float phi0=(M_PI*2.f/20*(i-.5)),phi1;
+  int x1=  cos(phi0)*radius+bw/2,x2;
+  int y1= -sin(phi0)*radius+bh/2,y2;
+
+  region_init();
+  region_new_area(x1,y1,1);
+  for(i=0;i<19;i++){
+    phi1=(M_PI*2.f/20*(i+.5));
+    x2=  cos(phi1)*radius+bw/2;
+    y2= -sin(phi1)*radius+bh/2;
+    region_arc_to(x2,y2,M_PI*.7);
   }
+  region_close_arc(M_PI*.7);
 
-  for(;i<n;i++){
-    v->x = rint( radiusx * .4 * cos( i*M_PI*12./n) + (bw>>1));
-    v->y = rint( radiusy * .4 * sin( i*M_PI*12./n) + (bh>>1));
-    v=v->next;
+  region_layout(g);
+}
+
+void arrange_region_ring(graph *g){
+  int bw=g->orig_width;
+  int bh=g->orig_height;
+  int radius=min(bw,bh)*.45;
+
+  region_init();
+  region_circle(bw/2,bh/2,radius,3);
+  region_circle(bw/2,bh/2,radius*.4,1);
+  region_layout(g);
+}
+
+void arrange_region_storm(graph *g){
+  int bw=g->orig_width;
+  int bh=g->orig_height;
+  int radius=min(bw,bh)*.45;
+  int i=0;
+
+  region_init();
+
+  for(i=0;i<10;i++){
+    float phi0=(M_PI*2.f/10*(i-.5));
+    float phi1=(M_PI*2.f/10*(i+.5));
+    int x1=  cos(phi0)*radius+bw/2;
+    int y1= -sin(phi0)*radius+bh/2;
+    int x2=  cos(phi1)*radius*.8+bw/2;
+    int y2= -sin(phi1)*radius*.8+bh/2;
+
+    region_new_area(x1,y1,1);
+    region_arc_to(x2,y2,M_PI*.2);
   }
 
+  region_circle(bw/2,bh/2,radius*.2,0);
+
+  region_layout(g);
 }
+
+void arrange_region_target(graph *g){
+  int bw=g->orig_width;
+  int bh=g->orig_height;
+  int radius=min(bw,bh)*.45;
+
+  region_init();
+  region_circle(bw/2,bh/2,radius,3);
+  region_circle(bw/2,bh/2,radius*.5,1);
+  region_circle(bw/2,bh/2,radius*.35,3);
+
+  region_layout(g);
+}
+
+void arrange_region_plus(graph *g){
+  region_init();
+
+  region_new_area(316,43,2);
+  region_arc_to(483,43,-M_PI*2/10);
+  region_line_to(483,216);
+  region_line_to(656,216);
+  region_arc_to(656,384,-M_PI*2/10);
+  region_line_to(483,384);
+  region_line_to(483,556);
+  region_arc_to(316,556,-M_PI*2/10);
+  region_line_to(316,384);
+  region_line_to(143,384);
+  region_arc_to(143,216,-M_PI*2/10);
+  region_line_to(316,216);
+  region_close_line();
+
+  region_layout(g);
+}
+
+void arrange_region_hole3(graph *g){
+  int bw=g->orig_width;
+  int bh=g->orig_height;
+  int radius=min(bw,bh)*.45;
+
+  region_init();
+  region_circle(bw/2,bh/2,radius,3);
+
+  region_new_area(400,200,2);
+  region_line_to(313,349);
+  region_line_to(487,349);
+  region_close_line();
+  region_layout(g);
+}
+
+void arrange_region_hole4(graph *g){
+  int bw=g->orig_width;
+  int bh=g->orig_height;
+  int radius=min(bw,bh)*.45;
+
+  region_init();
+  region_circle(bw/2,bh/2,radius,3);
+
+  region_new_area(325,225,1);
+  region_line_to(475,225);
+  region_line_to(475,375);
+  region_line_to(325,375);
+  region_close_line();
+  region_layout(g);
+}
+
+void arrange_region_ovals(graph *g){
+
+
+  region_init();
+  region_new_area(270,163,2);
+  region_arc_to(530,163,-M_PI*.99);
+  region_line_to(530,437);
+  region_arc_to(270,437,-M_PI*.99);
+  region_close_line();
+
+  region_new_area(80,263,2);
+  region_arc_to(230,263,-M_PI*.99);
+  region_line_to(230,337);
+  region_arc_to(80,337,-M_PI*.99);
+  region_close_line();
+
+  region_new_area(570,263,2);
+  region_arc_to(720,263,-M_PI*.99);
+  region_line_to(720,337);
+  region_arc_to(570,337,-M_PI*.99);
+  region_close_line();
+
+
+  region_layout(g);
+  
+
+}

Modified: trunk/planarity/graph_arrange.h
===================================================================
--- trunk/planarity/graph_arrange.h	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/graph_arrange.h	2005-10-14 12:22:47 UTC (rev 10156)
@@ -33,4 +33,17 @@
 extern void arrange_verticies_mesh(graph *g, int width, int height);
 extern void arrange_verticies_nastymesh(graph *g, int w, int h, vertex **flat);
 
-extern void arrange_verticies_cloud(graph *g);
+
+extern void arrange_region_star(graph *g);
+extern void arrange_region_rainbow(graph *g);
+extern void arrange_region_dashed_circle(graph *g);
+extern void arrange_region_bifur(graph *g);
+extern void arrange_region_dairyqueen(graph *g);
+extern void arrange_region_cloud(graph *g);
+extern void arrange_region_ring(graph *g);
+extern void arrange_region_storm(graph *g);
+extern void arrange_region_target(graph *g);
+extern void arrange_region_plus(graph *g);
+extern void arrange_region_hole3(graph *g);
+extern void arrange_region_hole4(graph *g);
+extern void arrange_region_ovals(graph *g);

Modified: trunk/planarity/graph_generate.c
===================================================================
--- trunk/planarity/graph_generate.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/graph_generate.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -40,52 +40,115 @@
   int unlock;
 } gen_instance;
 
-#define FINITE_LEVELS 23
+#define FINITE_LEVELS 79
 static gen_instance i_list[FINITE_LEVELS]={ 
 
-  {"simple",   1, "A Small Beginning",                              generate_simple,    1.,1., 1 }, // 1
-  {"simple",   2, "My First Real Level(tm)",                        generate_simple,    1.,1., 2 }, // 2
-  {"data",     0, "My First Mission Impossible(tm)",                generate_data,     20.,1., 3 }, // 3
-  {"simple",   3, "Larger But Not Harder",                          generate_simple,    1.,1., 2 }, // 4
-  {"crest",    5, "The Trick Is It's Easy",                         generate_crest,     1.,1., 2 }, // 5
+  {"simple",   1, "A Small Beginning",                              generate_simple,    1.,4., 1 }, // 1
+  {"simple",   2, "My First Real Level(tm)",                        generate_simple,    1.,4., 2 }, // 2
+  {"data",     0, "My First Mission Impossible(tm)",                generate_data,     20.,4., 3 }, // 3
+  {"simple",   3, "Larger But Not Harder",                          generate_simple,    1.,4., 2 }, // 4
+  {"crest",    5, "The Trick Is It's Easy",                         generate_crest,     1.,4., 2 }, // 5
 
-  {"simple",   4, "Practice Before the Handbasket: One of Three",   generate_simple,    1.,1., 2 }, // 6
-  {"simple",   5, "Practice Before the Handbasket: Two of Three",   generate_simple,    1.,1., 2 }, // 7
-  {"simple",   6, "Practice Before the Handbasket: Three of Three", generate_simple,    1.,1., 2 }, // 8
+  {"simple",   4, "Practice Before the Handbasket: One of Three",   generate_simple,    1.,4., 2 }, // 6
+  {"simple",   5, "Practice Before the Handbasket: Two of Three",   generate_simple,    1.,4., 2 }, // 7
+  {"simple",   6, "Practice Before the Handbasket: Three of Three", generate_simple,    1.,4., 2 }, // 8
 
-  {"sparse",   4, "Tough and Stringy",                              generate_sparse,    1.2,1., 2 }, // 9
-  {"sparse",   5, "Threadbare",                                     generate_sparse,    1.2,1., 2 }, // 10
+  {"sparse",   4, "Tough and Stringy",                              generate_sparse,    1.2,4., 2 }, // 9
+  {"sparse",   5, "Threadbare",                                     generate_sparse,    1.2,4., 2 }, // 10
 
-  {"nasty",    4, "The Bumpy Circles Are Slightly More Difficult",  generate_nasty,    1.5,1., 3 }, // 11
-  {"nasty",    5, "Three is a Magic Number",                        generate_nasty,    1.5,1., 3 }, // 12
-  {"nasty",    6, "Last Call For (Sort of) Triangles (For Now)",    generate_nasty,    1.5,1., 3 }, // 13
+  {"nasty",    4, "The Bumpy Circles Are Slightly More Difficult",  generate_nasty,    1.5,4., 3 }, // 11
+  {"nasty",    5, "Three is a Magic Number",                        generate_nasty,    1.5,4., 3 }, // 12
+  {"nasty",    6, "Last Call For (Sort of) Triangles (For Now)",    generate_nasty,    1.5,4., 3 }, // 13
 
-  {"free",     4, "Something Only Subtly Different",                generate_freeform, 1.5,1., 3 }, // 14
-  {"free",     5, "It Can Roll! Granted, Not Very Well",            generate_freeform, 1.5,1., 3 }, // 15
-  {"free",     6, "If You Squint, It's a Round Brick",              generate_freeform, 1.5,1., 3 }, // 16
+  {"free",     4, "Something Only Subtly Different",                generate_freeform, 1.5,4., 3 }, // 14
+  {"free",     5, "It Can Roll! Granted, Not Very Well",            generate_freeform, 1.5,4., 3 }, // 15
+  {"free",     6, "If You Squint, It's a Round Brick",              generate_freeform, 1.5,4., 3 }, // 16
 
-  {"rogue",    5, "A New Objective",                                generate_rogue,    1.6,1., 3 }, // 17
-  {"rogue",    6, "How Low Can You Go?",                            generate_rogue,    1.6,1., 3 }, // 18
-  {"rogue",    7, "Military Industrial Complex",                    generate_rogue,    1.6,1., 4 }, // 19
+  {"rogue",    5, "A New Objective",                                generate_rogue,    1.6,4., 3 }, // 17
+  {"rogue",    6, "How Low Can You Go?",                            generate_rogue,    1.6,4., 3 }, // 18
+  {"rogue",    7, "Military Industrial Complex",                    generate_rogue,    1.6,4., 4 }, // 19
 
-  {"embed",    4, "The Hexagon is a Subtle and Wily Beast",         generate_embed,     2.,1.,  4 }, // 20
-  {"embed",    5, "No, Really, The Hexagon Puzzles Are Harder",     generate_embed,     3.,1.,  5 }, // 21
-  {"embed",    6, "Cursed?  Call 1-800-HEX-A-GON Today!",           generate_embed,     4.,1.,  6 }, // 22
+  {"embed",    4, "The Hexagon is a Subtle and Wily Beast",         generate_embed,     2.,4.,  4 }, // 20
+  {"embed",    5, "No, Really, The Hexagon Puzzles Are Harder",     generate_embed,     3.,4.,  5 }, // 21
+  {"embed",    6, "Cursed?  Call 1-800-HEX-A-GON Today!",           generate_embed,     4.,4.,  6 }, // 22
 
-  {"simple",   7, "Round but Straightforward",                      generate_simple,    1.,1.,  4 }, // 23
+  {"simple",   7, "Round but Straightforward",                      generate_simple,    1.,4.,  4 }, // 23
 
-  //{"cloud", 9, "More of a Mess Than Usual",   generate_mesh_1_cloud, 2.,1., 3 }, // 9
+  {"shape",    0, "A Star Is Born... Then Solved",                  generate_shape,    1.,2.,  6 }, // 24
+  {"shape",    1, "Oh, Rain*bows*...",                              generate_shape,    1.,2.,  6 }, // 25
+  {"shape",    2, "Solve Along the Dotted Line",                    generate_shape,    1.,2.,  6 }, // 26
+  {"shape",    3, "Using All Available Space",                      generate_shape,    1.,2.,  6 }, // 27
+  {"shape",    4, "Brainfreeze",                                    generate_shape,    1.,2.,  6 }, // 28
+  {"shape",    6, "Tropical Storm Invest",                          generate_shape,    1.,2.,  6 }, // 30
+
+  {"dense",  8, "Algorithm: Original/Dense (Order: 8)", generate_dense,     .8,1., 5 }, // 31
+  {"simple", 8, "Algorithm: Original (Order: 8)",       generate_simple,    1.,1., 6 }, // 32
+  {"sparse", 8, "Algorithm: Original/Sparse (Order: 8)",generate_sparse,   1.2,1., 7 }, // 33
+  {"nasty",  8, "Algorithm: Nasty (Order: 8)",          generate_nasty,    1.5,1., 8 }, // 34
+  {"free",   8, "Algorithm: Freeform/4 (Order: 8)",     generate_freeform, 1.5,1., 9 }, // 35
+  {"rogue",  8, "Algorithm: Rogue (Order: 8)",          generate_rogue,    1.6,1.,10 }, // 36
+  {"embed",  8, "Algorithm: Embed (Order: 8)",          generate_embed,     4.,1.,10 }, // 37
+  {"shape",  7, "Operator",                             generate_shape,     1.,2.,10 }, // 38
+
+  {"dense",  9, "Algorithm: Original/Dense (Order: 9)", generate_dense,     .8,1., 5 }, // 39
+  {"simple", 9, "Algorithm: Original (Order: 9)",       generate_simple,    1.,1., 6 }, // 40
+  {"sparse", 9, "Algorithm: Original/Sparse (Order: 9)",generate_sparse,   1.2,1., 7 }, // 41
+  {"nasty",  9, "Algorithm: Nasty (Order: 9)",          generate_nasty,    1.5,1., 8 }, // 42
+  {"free",   9, "Algorithm: Freeform/4 (Order: 9)",     generate_freeform, 1.5,1., 9 }, // 43
+  {"rogue",  9, "Algorithm: Rogue (Order: 9)",          generate_rogue,    1.6,1.,10 }, // 44
+  {"embed",  9, "Algorithm: Embed (Order: 9)",          generate_embed,     4.,1.,10 }, // 45
+  {"shape",  8, "The Inside Is Pointy",                 generate_shape,     1.,2.,10 }, // 46
+
+  {"dense", 10, "Algorithm: Original/Dense (Order: 10)", generate_dense,     .8,1., 5 }, // 47
+  {"simple",10, "Algorithm: Original (Order: 10)",       generate_simple,    1.,1., 6 }, // 48
+  {"sparse",10, "Algorithm: Original/Sparse (Order: 10)",generate_sparse,   1.2,1., 7 }, // 49
+  {"nasty", 10, "Algorithm: Nasty (Order: 10)",          generate_nasty,    1.5,1., 8 }, // 50
+  {"free",  10, "Algorithm: Freeform/4 (Order: 10)",     generate_freeform, 1.5,1., 9 }, // 51
+  {"rogue", 10, "Algorithm: Rogue (Order: 10)",          generate_rogue,    1.6,1.,10 }, // 52
+  {"embed", 10, "Algorithm: Embed (Order: 10)",          generate_embed,     4.,1.,10 }, // 53
+  {"shape",  9, "Riches and Good Luck",                  generate_shape,     1.,2.,10 }, // 54
+
+  {"dense", 11, "Algorithm: Original/Dense (Order: 11)", generate_dense,     .8,1., 5 }, // 55
+  {"simple",11, "Algorithm: Original (Order: 11)",       generate_simple,    1.,1., 6 }, // 56
+  {"sparse",11, "Algorithm: Original/Sparse (Order: 11)",generate_sparse,   1.2,1., 7 }, // 57
+  {"nasty", 11, "Algorithm: Nasty (Order: 11)",          generate_nasty,    1.5,1., 8 }, // 58
+  {"free",  11, "Algorithm: Freeform/4 (Order: 11)",     generate_freeform, 1.5,1., 9 }, // 59
+  {"rogue", 11, "Algorithm: Rogue (Order: 11)",          generate_rogue,    1.6,1.,10 }, // 60
+  {"embed", 11, "Algorithm: Embed (Order: 11)",          generate_embed,     4.,1.,10 }, // 61
+  {"shape", 10, "Mmmm... Doughnut",                      generate_shape,     1.,2.,10 }, // 62
+
+  {"dense", 12, "Algorithm: Original/Dense (Order: 12)", generate_dense,     .8,1., 5 }, // 63
+  {"simple",12, "Algorithm: Original (Order: 12)",       generate_simple,    1.,1., 6 }, // 64
+  {"sparse",12, "Algorithm: Original/Sparse (Order: 12)",generate_sparse,   1.2,1., 7 }, // 65
+  {"nasty", 12, "Algorithm: Nasty (Order: 12)",          generate_nasty,    1.5,1., 8 }, // 66
+  {"free",  12, "Algorithm: Freeform/4 (Order: 12)",     generate_freeform, 1.5,1., 9 }, // 67
+  {"rogue", 12, "Algorithm: Rogue (Order: 12)",          generate_rogue,    1.6,1.,10 }, // 68
+  {"embed", 12, "Algorithm: Embed (Order: 12)",          generate_embed,     4.,1.,10 }, // 69
+  {"shape", 11, "Quick and Dirty, or Slow and Steady",   generate_shape,     1.,1.,10 }, // 70
+  {"shape",  5, "Little Fluffy Clouds",                   generate_shape,    1.,2., 6 }, // 29
+
+  {"dense", 13, "Algorithm: Original/Dense (Order: 13)", generate_dense,     .8,1., 5 }, // 71
+  {"simple",13, "Algorithm: Original (Order: 13)",       generate_simple,    1.,1., 6 }, // 72
+  {"sparse",13, "Algorithm: Original/Sparse (Order: 13)",generate_sparse,   1.2,1., 7 }, // 73
+  {"nasty", 13, "Algorithm: Nasty (Order: 13)",          generate_nasty,    1.5,1., 8 }, // 74
+  {"free",  13, "Algorithm: Freeform/4 (Order: 13)",     generate_freeform, 1.5,1., 9 }, // 75
+  {"rogue", 13, "Algorithm: Rogue (Order: 13)",          generate_rogue,    1.6,1.,10 }, // 76
+  {"embed", 13, "Algorithm: Embed (Order: 13)",          generate_embed,     4.,1.,10 }, // 77
+  {"shape", 12, "A Sudden Urge To Go Shopping",          generate_shape,     1.,1.,10 }, // 78
+  {"shape", 13, "Sweet Reward",                          generate_shape,     1.,1.,10 }, // 79
+
 };
 
-#define LOOP_LEVELS 7
+#define LOOP_LEVELS 8
 static gen_instance i_list_loop[LOOP_LEVELS]={ 
-  {"dense",  8, "Algorithm: Original/Dense (Order: %d)", generate_dense,     .8,1., 5 }, // n
-  {"simple", 8, "Algorithm: Original (Order: %d)",       generate_simple,    1.,1., 5 }, // n
-  {"sparse", 8, "Algorithm: Original/Sparse (Order: %d)",generate_sparse,   1.2,1., 5 }, // n
-  {"nasty",  8, "Algorithm: Nasty (Order: %d)",          generate_nasty,    1.5,1., 5 }, // n
-  {"free",   8, "Algorithm: Freeform/4 (Order: %d)",     generate_freeform, 1.5,1., 5 }, // n
-  {"rogue",  8, "Algorithm: Rogue (Order: %d)",          generate_rogue,    1.6,1., 5 }, // n
-  {"embed",  8, "Algorithm: Embed (Order: %d)",          generate_embed,     4.,1., 5 }, // n
+  {"dense", 14, "Algorithm: Original/Dense (Order: %d)", generate_dense,     .8,1., 5 }, // n
+  {"simple",14, "Algorithm: Original (Order: %d)",       generate_simple,    1.,1., 6 }, // n
+  {"sparse",14, "Algorithm: Original/Sparse (Order: %d)",generate_sparse,   1.2,1., 7 }, // n
+  {"nasty", 14, "Algorithm: Nasty (Order: %d)",          generate_nasty,    1.5,1., 8 }, // n
+  {"free",  14, "Algorithm: Freeform/4 (Order: %d)",     generate_freeform, 1.5,1., 9 }, // n
+  {"rogue", 14, "Algorithm: Rogue (Order: %d)",          generate_rogue,    1.6,1.,10 }, // n
+  {"embed", 14, "Algorithm: Embed (Order: %d)",          generate_embed,     4.,1.,10 }, // n
+  {"shape", 14, "Algorithm: Region (Order: %d)",         generate_shape,     1.,2.,10 },
 };
 
 int generate_find_number(char *id){

Modified: trunk/planarity/graph_generate.h
===================================================================
--- trunk/planarity/graph_generate.h	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/graph_generate.h	2005-10-14 12:22:47 UTC (rev 10156)
@@ -36,6 +36,7 @@
 extern void generate_embed(graph *g, int order);
 extern void generate_crest(graph *g, int order);
 
-extern void generate_freeform(graph *g, int order);
 
 extern void generate_data(graph *g, int order);
+extern void generate_freeform(graph *g, int order);
+extern void generate_shape(graph *g, int order);

Modified: trunk/planarity/graph_generate_mesh1.c
===================================================================
--- trunk/planarity/graph_generate_mesh1.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/graph_generate_mesh1.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -88,7 +88,7 @@
   while(el){
     edge *e = el->edge;
     
-    if(intersects(A,B,e->A,e->B,&dummy_x,&dummy_y))
+    if(intersectsV(A,B,e->A,e->B,&dummy_x,&dummy_y))
       return 1;
 
     el=el->next;
@@ -556,7 +556,7 @@
   int count=0;
 
   while(e){
-    if(intersects(A,B,e->A,e->B,&dummy_x,&dummy_y))
+    if(intersectsV(A,B,e->A,e->B,&dummy_x,&dummy_y))
       count++;
     e=e->next;
   }

Modified: trunk/planarity/graph_generate_mesh2.c
===================================================================
--- trunk/planarity/graph_generate_mesh2.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/graph_generate_mesh2.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -33,6 +33,7 @@
 #include "gameboard.h"
 #include "graph_generate.h"
 #include "graph_arrange.h"
+#include "graph_region.h"
 
 /* Mesh1 has three primary considerations in mind:
    1) By default, act like the algorithm in the original planarity
@@ -51,29 +52,41 @@
 } mesh;
 
 // check for intersections with other edges
-static int check_intersects_edge(mesh *m, edge *e){
+static int check_intersects_edge(mesh *m, edge *e, int intersections){
   edge *ge = m->g->edges;
+  int count=0;
+
   while(ge){
     double xo,yo;
-    if(intersects(ge->A,ge->B,e->A,e->B,&xo,&yo))return 1;
+
+    // edges that share a vertex don't intersect by definition
+    if(ge->A!=e->A && ge->A!=e->B && ge->B!=e->A && ge->B!=e->B)
+      if(intersects(ge->A->orig_x,ge->A->orig_y,
+		    ge->B->orig_x,ge->B->orig_y,
+		    e->A->orig_x,e->A->orig_y,
+		    e->B->orig_x,e->B->orig_y,
+		    &xo,&yo)){
+	count++;
+	if(count>intersections)return 1;
+      }
     ge=ge->next;
   }
   return 0;
 }
 
 static float dot(vertex *A, vertex *B, vertex *C){
-  return (float)(B->x-A->x)*(float)(C->x-B->x) + 
-    (float)(B->y-A->y)*(float)(C->y-B->y);
+  return (float)(B->orig_x-A->orig_x)*(float)(C->orig_x-B->orig_x) + 
+    (float)(B->orig_y-A->orig_y)*(float)(C->orig_y-B->orig_y);
 }
 
 static float cross(vertex *A, vertex *B, vertex *C){
-  return (float)(B->x-A->x)*(float)(C->y-A->y) - 
-    (float)(B->y-A->y)*(float)(C->x-A->x);
+  return (float)(B->orig_x-A->orig_x)*(float)(C->orig_y-A->orig_y) - 
+    (float)(B->orig_y-A->orig_y)*(float)(C->orig_x-A->orig_x);
 }
 
 static float sq_point_distance(vertex *A, vertex *B){
-  float xd = A->x-B->x;
-  float yd = A->y-B->y;
+  float xd = A->orig_x-B->orig_x;
+  float yd = A->orig_y-B->orig_y;
   return xd*xd+yd*yd;
 }
 
@@ -95,120 +108,247 @@
   vertex *v = m->g->verticies;
 
   while(v){
-    if(v!=e->A && v!=e->B && sq_line_distance(e,v)<100)return 1;
+    if(v!=e->A && v!=e->B && sq_line_distance(e,v)<16)return 1;
     v=v->next;
   }
 
   return 0;
 }
 
-// Although very inefficient, it is simple and correct.  Even
-// impossibly large boards generate in a fraction of a second on old
-// boxen.  There's likely no need to bother optimizing this step of
-// board creation. */
-static void span_depth_first2(mesh *m,vertex *current, float length_limit){
+static int select_available(mesh *m,vertex *current,float length_limit,int intersections){
+  int count=0;
+  vertex *v = m->g->verticies;
 
-  while(1){
-    // Mark/count all possible choices
-    int count=0;
-    int count2=0;
-    int choice;
-    vertex *v = m->g->verticies;
-
-    while(v){
-      v->selected = 0;
-      if(!v->edges && v!=current){
-	if(sq_point_distance(v,current)<=length_limit){
+  // mark all possible choices
+  while(v){
+    v->selected = 0;
+    if(v!=current){
+      if(length_limit==0 || sq_point_distance(v,current)<=length_limit){
+	if(!exists_edge(v,current)){
 	  edge e;
 	  e.A = v;
 	  e.B = current;
-	  if(!check_intersects_edge(m,&e)){
-	    if(!check_intersects_vertex(m,&e)){
-	      v->selected = 1;
-	      count++;
+	  if(!region_intersects(&e)){
+	    if(!check_intersects_edge(m,&e,intersections)){
+	      if(!check_intersects_vertex(m,&e)){
+		v->selected=1;
+		count++;
+	      }
 	    }
 	  }
 	}
       }
-      v=v->next;
     }
+    v=v->next;
+  }
 
-    if(count == 0) return;
-    
-    choice = random_number()%count;
-    count2 = 0;
-    v = m->g->verticies;
-    while(v){
-      if(v->selected){
-	if(count2++ == choice){
-	  add_edge(m->g,v,current);
-	  span_depth_first2(m,v, length_limit);
-	  break;
-	}
-      }
-      v=v->next;
+  return count;
+}
+
+// Although very inefficient, it is simple and correct.  Even
+// impossibly large boards generate in a fraction of a second on old
+// boxen.  There's likely no need to bother optimizing this step of
+// board creation. */
+
+typedef struct insort{
+  int metric;
+  vertex *v;
+} insort;
+
+static int insort_c(const void *a, const void *b){
+  insort *A=(insort *)a;
+  insort *B=(insort *)b;
+  return(A->metric-B->metric);
+}
+
+static vertex *vertex_num_sel(graph *g,int num){
+  vertex *v=g->verticies;
+  if(num<0)return 0;
+  while(v){
+    if(v->selected){
+      if(!num)
+	break;
+      else
+	num--;
     }
-    
-    if(count == 1) return; // because we just took care of it
+    v=v->next;
   }
+  return v;
 }
 
-static void random_populate(mesh *m,vertex *current,int dense_128, float length_limit){
-  int num_edges=0,count=0;
-  edge_list *el=current->edges;
-  vertex *v = m->g->verticies;
-  while(el){
-    num_edges++;
-    el=el->next;
+static void prepopulate(mesh *m,int length_limit){
+  // sort all verticies in ascending order by their number of potential edges 
+  int i=0;
+  insort index[m->g->vertex_num];
+  vertex *v=m->g->verticies;
+
+  while(v){
+    index[i].v=v;
+    index[i].metric = select_available(m,v,0,0);
+    i++;
+    v=v->next;
   }
+  qsort(index,m->g->vertex_num,sizeof(*index),insort_c);
 
-  // mark all possible choices
-  while(v){
-    v->selected = 0;
-    if(v!=current){
-      if(sq_point_distance(v,current)<=length_limit){
-	if(!exists_edge(v,current)){
-	  edge e;
-	  e.A = v;
-	  e.B = current;
-	  if(!check_intersects_edge(m,&e)){
-	    if(!check_intersects_vertex(m,&e)){
-	      v->selected=1;
-	      count++;
+  // populate in ascending order
+  for(i=0;i<m->g->vertex_num;i++){
+    int intersections=0;
+    int edges=0;
+    v = index[i].v;
+    
+    // does this vertex already have edges?
+    {
+      edge_list *el=v->edges;
+      while(el){
+	edges++;
+	el=el->next;
+	if(edges>=2)break;
+      }
+    }
+    if(edges>=2)continue;
+
+    // it's possible some intersections will be necessary, but go for
+    // fewest possible
+    while(edges<2 && intersections<10){
+      int count = select_available(m,v,length_limit,intersections);
+      if(count){
+	vertex *short0=0;
+	vertex *short1=0;
+	vertex *w=m->g->verticies;
+	long d0;
+	long d1;
+	
+	if(length_limit){
+	  // choose two at random 
+	  int a=random_number()%count;
+	  int b=-1;
+
+	  if(count>1)
+	    while(b==-1){
+	      b=random_number()%count;
+	      if(b==a)b=-1;
 	    }
+
+	  short0=vertex_num_sel(m->g,a);
+	  short1=vertex_num_sel(m->g,b);
+
+	}else{
+	  // used with region-constrined meshes
+	  // of the possible edges, choose the shortest two
+	  while(w){
+	    if(w!=v && w->selected){
+	      int xd=w->orig_x-v->orig_x;
+	      int yd=w->orig_y-v->orig_y;
+	      long d=xd*xd+yd*yd;
+	      if(!short0){
+		short0=w;
+		d0=d;
+	      }else if(!short1 || d<d1){
+		if(d<d0){
+		  short1=short0;
+		  d1=d0;
+		  short0=w;
+		  d0=d;
+		}else{
+		  short1=w;
+		  d1=d;
+		}
+	      }
+	    }
+	    w=w->next;
 	  }
 	}
+	
+	if(short0){
+	  add_edge(m->g,v,short0);
+	  edges++;
+	  m->g->objective +=intersections;
+	  if(intersections)m->g->objective_lessthan=1;
+	}
+	if(edges<2 && short1){
+	  add_edge(m->g,v,short1);
+	  edges++;
+	  m->g->objective +=intersections;
+	  if(intersections)m->g->objective_lessthan=1;
+	}
       }
+      intersections++;
     }
-    v=v->next;
   }
+}
 
-  // make sure no vertex is a leaf
-  if(num_edges<2){
-    int choice = random_number() % count;
-    count = 0;
-    
-    v = m->g->verticies;
-    while(v){
-      if(v->selected){
-	if(count++ == choice){
-	  add_edge(m->g,v,current);
-	  v->selected=0;
-	  break;
+// the spanning walk is to make an attempt at a single, connected graph.
+static void span_depth_first2(mesh *m,vertex *current, float length_limit){
+  
+  current->grabbed=1; // overloaded; "we walked this already"
+  while(1){
+    // prefer walking along edges that already exist
+    {
+      edge_list *el=current->edges;
+      
+      while(el){
+	edge *e=el->edge;
+	vertex *v;
+	if(e->A==current)
+	  v=e->B;
+	else
+	  v=e->A;
+
+	if(!v->grabbed){
+	  span_depth_first2(m, v, length_limit);
 	}
+
+	el=el->next;
       }
-      v=v->next;
     }
+
+    // now walk any possible edges that have not been walked
+    {
+      int count=select_available(m,current,length_limit,0);
+      int count2=0;
+      int choice;
+      vertex *v = m->g->verticies;
+      
+      // filter out already-walked edges 
+      while(v){
+	if(v->grabbed && v->selected){ // grabbed is also overloaded to mean not walked
+	  v->selected = 0;
+	  count--;
+	}
+	v=v->next;
+      }
+     
+      if(count == 0) return;
+      
+      choice = random_number()%count;
+      v = m->g->verticies;
+      while(v){
+	if(v->selected){
+	  if(count2++ == choice){
+	    add_edge(m->g,v,current);
+	    span_depth_first2(m,v, length_limit);
+	    break;
+	  }
+	}
+	v=v->next;
+      }
+    
+      if(count == 1) return; // because we just took care of it
+    }
   }
+}
 
-  // now, random populate
-  v = m->g->verticies;
-  while(v){
-    if(v->selected && random_yes(dense_128)){
-      add_edge(m->g,v,current);
-      v->selected=0;
+static void random_populate(mesh *m,vertex *current,int dense_128, float length_limit){
+  int count=select_available(m,current,length_limit,0);
+  if(count){
+    vertex *v = m->g->verticies;
+    while(v){
+      if(v->selected && random_yes(dense_128)){
+	add_edge(m->g,v,current);
+	v->selected=0;
+      }
+      v=v->next;
     }
-    v=v->next;
   }
 }
 
@@ -269,6 +409,7 @@
   }
 
   new_board(g, m->width * m->height);
+  region_init(); // clear it
 
   // used for intersection calcs
   {
@@ -276,8 +417,8 @@
     vertex *v = g->verticies;
     for(y=0;y<m->height;y++)
       for(x=0;x<m->width;x++){
-	v->x=x*50; // not a random number
-	v->y=y*50; // not a random number
+	v->orig_x=x*50; // not a random number
+	v->orig_y=y*50; // not a random number
 	v=v->next;
       }
   }
@@ -292,16 +433,42 @@
 
   length_limit*=50;
   length_limit*=length_limit;
-  
-  /* first walk a random spanning tree */
-  span_depth_first2(m, m->g->verticies, length_limit);
-  
+
+  if(have_region())
+    prepopulate(m,0);
+
+  /* connect the graph into as few discrete sections as possible */
+  v = m->g->verticies;
+  while(v){
+    v->grabbed = 0;
+    v=v->next;
+  }
+
+  v = m->g->verticies;
+  // make sure we walk all verticies
+  while(v){
+    if(!v->grabbed)
+      span_depth_first2(m, m->g->verticies, length_limit);
+    v=v->next;
+  }
+
+  if(!have_region())
+    prepopulate(m,length_limit);
+
   /* now iterate the whole mesh adding random edges */
   v=m->g->verticies;
   while(v){
     random_populate(m, v, density_128, length_limit);
     v=v->next;
   }
+
+  /* clear out overloaded flags */
+  v=m->g->verticies;
+  while(v){
+    v->grabbed=0;
+    v=v->next;
+  }
+
   deselect_verticies(m->g);
 }
 
@@ -310,12 +477,94 @@
   random_seed(order+1);
   mesh_setup(g, &m, order, 0);
 
-  generate_mesh2(&m,48,5);
-  //arrange_verticies_mesh(g,m.width,m.height);
+  generate_mesh2(&m,48,4);
 
   randomize_verticies(g);
   if(order*.03<.3)
     arrange_verticies_polycircle(g,4,0,order*.03,0,0,0);
   else
     arrange_verticies_polycircle(g,4,0,.3,0,0,0);
+
 }
+
+void generate_shape(graph *g, int order){
+  int mod=0;
+  int dens=64;
+  int min=8;
+  mesh m;
+  random_seed(order+1);
+
+  switch(order%13){
+  case 0: // star
+    mod=10; break;
+  case 1:
+    break;
+  case 2: // dashed circle
+    dens=48; break;
+  case 3: // bifur
+    dens=80; break;
+  case 4:
+    break;
+  case 5:
+    min = 12;
+    dens = 10;
+    break;
+  case 6:
+    min = 10;
+    break;
+  case 7:
+    min = 10;
+    break;
+  case 8:
+    min = 10;
+    break;
+  case 9:
+    min = 10;
+    break;
+  case 10: // ring
+    dens=128;
+    min = 11;
+    break;
+  case 11:
+    min = 12;
+    break;
+  case 12: // target
+    dens=128;
+    min = 14;
+    break;
+  }
+
+  mesh_setup(g, &m, (order>min?order:min), mod);
+  randomize_verticies(g);
+
+  switch(order % 13){
+  case 0: // star
+    arrange_region_star(g); break; //4
+  case 1: // rainbow
+    arrange_region_rainbow(g); break; //9
+  case 2: // dashed circle
+    arrange_region_dashed_circle(g); break; //0
+  case 3: // bifur
+    arrange_region_bifur(g); break; //0
+  case 4: // dairyqueen
+    arrange_region_dairyqueen(g); break; //0
+  case 5: // cloud
+    arrange_region_cloud(g); break; //0
+  case 6: // storm
+    arrange_region_storm(g); break; //11
+  case 7: // plus;
+      arrange_region_plus(g); break; //2
+  case 8: 
+    arrange_region_hole3(g); break; //4
+  case 9: 
+    arrange_region_hole4(g); break; //15
+  case 10: // ring
+    arrange_region_ring(g); break; //29
+  case 11: 
+    arrange_region_ovals(g); break; //95
+  case 12: // target
+    arrange_region_target(g); break; //108
+  }
+
+  generate_mesh2(&m,dens,0);
+}

Added: trunk/planarity/graph_region.c
===================================================================
--- trunk/planarity/graph_region.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/graph_region.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -0,0 +1,830 @@
+/*
+ *
+ *  gPlanarity: 
+ *     The geeky little puzzle game with a big noodly crunch!
+ *    
+ *     gPlanarity copyright (C) 2005 Monty <monty at xiph.org>
+ *     Original Flash game by John Tantalo <john.tantalo at case.edu>
+ *     Original game concept by Mary Radcliffe
+ *
+ *  gPlanarity is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *   
+ *  gPlanarity is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *   
+ *  You should have received a copy of the GNU General Public License
+ *  along with Postfish; see the file COPYING.  If not, write to the
+ *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "graph.h"
+#include "graph_region.h"
+
+/* Regions are 'electric fences' for mesh building; used in mesh2 to
+   make non-convex shapes */
+
+typedef struct region_segment {
+  int layout; /* 0 no layout, 1 left, 2 right, 3 layout-only */
+  int cont;   /* is this continuous from last line? */
+
+  float x1;
+  float y1;
+  float x2;
+  float y2;
+
+  // arc computation cache (if arc)
+  float cx;
+  float cy;
+  float radius;
+  float phi0;
+  float phi1;
+  float phi;
+
+  float length;
+  struct region_segment *next;
+} region_segment;
+
+typedef struct region{
+  int num;
+  region_segment *l;
+
+  int ox,oy,x,y;
+  int layout;
+
+  int cont;
+} region;
+
+static region r;
+static region layout_adj;
+static region_segment *segpool=0;
+
+#define CHUNK 64
+
+static region_segment *new_segment(region *r, int x1,int y1,int x2, int y2){
+  region_segment *ret;
+  
+  if(!segpool){
+    int i;
+    segpool = calloc(CHUNK,sizeof(*segpool));
+    for(i=0;i<CHUNK-1;i++) /* last addition's next points to nothing */
+      segpool[i].next=segpool+i+1;
+  }
+
+  ret=segpool;
+  segpool=ret->next;
+
+  memset(ret,0,sizeof(*ret));
+  ret->next = r->l;
+  ret->layout=r->layout;
+  ret->x1=x1;
+  ret->y1=y1;
+  ret->x2=x2;
+  ret->y2=y2;
+  ret->cont = r->cont;
+
+  r->l=ret;
+  
+  return ret;
+}
+
+/* angle convention: reversed y (1,-1 is first quadrant, ala X
+   windows), range -PI to PI */
+
+static int intersects_arc(edge *e, region_segment *r){
+  float Ax = e->A->x - r->cx;
+  float Ay = e->A->y - r->cy;
+  float Bx = e->B->x - r->cx;
+  float By = e->B->y - r->cy;
+
+  float dx = Bx - Ax;
+  float dy = By - Ay;
+  float dr2 = dx*dx + dy*dy;
+  float D = Ax*By - Bx*Ay;
+  float discriminant =(r->radius*r->radius)*dr2 - D*D; 
+
+  // does it even intersect the full circle?
+  if(discriminant<=0)return 0;
+  
+  {
+    float x1,y1,x2,y2;
+    
+    float sqrtd = sqrt(discriminant);
+    float sign = (dy>0?1.f:-1.f);
+
+    // finite precision required here else 0/inf slope lines will be
+    // slighly off the secant
+    x1 = rint((D*dy + sign*dx*sqrtd) / dr2);
+    x2 = rint((D*dy - sign*dx*sqrtd) / dr2);
+
+    y1 = rint((-D*dx + fabs(dy)*sqrtd) / dr2);
+    y2 = rint((-D*dx - fabs(dy)*sqrtd) / dr2);
+
+    Ax = rint(Ax);
+    Ay = rint(Ay);
+    Bx = rint(Bx);
+    By = rint(By);
+
+    // is x1,y1 actually on the segment?
+    if( !(x1<Ax && x1<Bx) &&
+	!(x1>Ax && x1>Bx) &&
+	!(y1<Ay && y1<By) &&
+	!(y1>Ay && y1>By)){
+      // yes. it is in the angle range we care about?
+
+      float ang = acos(x1 / r->radius);
+      if(y1>0) ang = -ang;
+      
+      if(r->phi<0){
+	if(r->phi0 < r->phi1){
+	  if(ang <= r->phi0 || ang >= r->phi1)return 1;
+	}else{
+	  if(ang <= r->phi0 && ang >= r->phi1)return 1;
+	}
+      }else{
+	if(r->phi0 < r->phi1){
+	  if(ang >= r->phi0 && ang <= r->phi1)return 1;
+	}else{
+	  if(ang >= r->phi0 || ang <= r->phi1)return 1;
+	}
+      }
+    }
+
+    // is x2,y2 actually on the segment?
+    // if so, it is in the arc range we care about?
+    if( !(x2<Ax && x2<Bx) &&
+	!(x2>Ax && x2>Bx) &&
+	!(y2<Ay && y2<By) &&
+	!(y2>Ay && y2>By)){
+      // yes. it is in the angle range we care about?
+
+      float ang = acos(x2 / r->radius);
+      if(y2>0) ang = -ang;
+      
+      if(r->phi<0){
+	if(r->phi0 < r->phi1){
+	  if(ang <= r->phi0 || ang >= r->phi1)return 1;
+	}else{
+	  if(ang <= r->phi0 && ang >= r->phi1)return 1;
+	}
+      }else{
+	if(r->phi0 < r->phi1){
+	  if(ang >= r->phi0 && ang <= r->phi1)return 1;
+	}else{
+	  if(ang >= r->phi0 || ang <= r->phi1)return 1;
+	}
+      }
+    }
+  }
+  return 0;
+}
+
+static float line_angle(float x1, float y1, float x2, float y2){
+  float xd = x2-x1;
+  float yd = y2-y1;
+  
+  if(xd == 0){
+    if(yd>0)
+      return -M_PI/2;
+    else
+      return M_PI/2;
+  }else if(xd<0){
+    if(yd<0)
+      return atan(-yd/xd)+M_PI;
+    else
+      return  atan(-yd/xd)-M_PI;
+  }else{
+    return atan(-yd/xd);
+  }
+}
+
+static float line_mag(float x1, float y1, float x2, float y2){
+  float xd = x2-x1;
+  float yd = y2-y1;
+  return hypot(xd,yd);
+}
+
+static void compute_arc(region_segment *r,float phi){
+  float x1=r->x1;
+  float y1=r->y1;
+  float x2=r->x2;
+  float y2=r->y2;
+  float ar,br,cr;
+  float cx,cy,a,c,d;
+  float xd = x2-x1;
+  float yd = y2-y1;
+  
+  if(phi<-M_PI){
+    ar = phi + M_PI*2;
+  }else if (phi<0){
+    ar = -phi;
+  }else if (phi<M_PI){
+    ar = phi;
+  }else{
+    ar = M_PI*2 - phi;
+  }
+
+  cr = line_angle(x1,y1,x2,y2);
+  a = line_mag(x1,y1,x2,y2)/2.f;
+  br=(M_PI/2.f)-(ar/2.f); 
+  c = tan(br)*a;
+  d = hypot(a,c);
+  
+  if(phi<-M_PI || (phi>0 && phi<M_PI)){
+    cx = x1 + cos(cr+M_PI/2)*c + xd/2;
+    cy = y1 - sin(cr+M_PI/2)*c + yd/2;
+  }else{
+    cx = x1 + cos(cr-M_PI/2)*c + xd/2;
+    cy = y1 - sin(cr-M_PI/2)*c + yd/2;
+  }
+  
+  r->cx=cx;
+  r->cy=cy;
+  r->radius=d;
+  
+  // have the center of the circle, have radius.  Determine the
+  // portion of the arc we want.
+  r->phi0 = acos( (x1-cx) / d);
+  r->phi1 = acos( (x2-cx) / d);
+  if(y1>cy) r->phi0= -r->phi0;
+  if(y2>cy) r->phi1= -r->phi1;
+  r->phi=phi;
+}
+
+static region_segment *region_arc(region *re, int x1, int y1, int x2, int y2, float rad){
+  region_segment *n=  new_segment(re,x1,y1,x2,y2);
+  compute_arc(n,rad);
+  return n;
+}
+
+static region_segment *region_line(region *re,int x1, int y1, int x2, int y2){
+  return new_segment(re,x1,y1,x2,y2);
+}
+
+/* The overall idea here is to massage the region segments and arcs
+   slightly so that when we layout points based on a region, the
+   layout is slightly inside or outside (as requested) the actual
+   region. This also reverses the path when rebuilding into the new
+   region, putting it in the order we actually need to evaluate it in.
+*/ 
+
+#define ADJ 2.f
+
+static void point_adj(float x1, float y1, float x2, float y2, float *Px, float *Py, int left){
+  float xd = x2-x1;
+  float yd = y2-y1;
+  float M = hypot(xd,yd);
+
+  if(left){
+    *Px +=  yd/M*ADJ;
+    *Py += -xd/M*ADJ;
+  }else{
+    *Px += -yd/M*ADJ;
+    *Py +=  xd/M*ADJ;
+  }
+}
+
+static void line_adj(float *x1, float *y1, float *x2, float *y2, int left){
+  float xd = *x2-*x1;
+  float yd = *y2-*y1;
+  float M = hypot(xd,yd);
+
+  if(left){
+    *x1 +=  yd/M*ADJ;
+    *x2 +=  yd/M*ADJ;
+    *y1 += -xd/M*ADJ;
+    *y2 += -xd/M*ADJ;
+  }else{
+    *x1 += -yd/M*ADJ;
+    *x2 += -yd/M*ADJ;
+    *y1 +=  xd/M*ADJ;
+    *y2 +=  xd/M*ADJ;
+  }
+
+  // make sure there's an overlap!
+  *x1-=xd/M*4.;
+  *x2+=xd/M*4.;
+  *y1-=yd/M*4.;
+  *y2+=yd/M*4.;
+}
+
+
+static float tangent_distance_from_center(float x1, float y1, float x2, float y2, 
+					  float cx, float cy){
+  float xd = x2 - x1;
+  float yd = y2 - y1;
+  return ((x2-x1)*(cy-y1) - (y2-y1)*(cx-x1)) / hypot(xd,yd);
+}
+
+static float radius_adjust(float r, float arc_phi, int left){
+  if(arc_phi<0){
+    if(left){
+      r+=ADJ;
+    }else{
+      r-=ADJ;
+    }
+  }else{
+    if(left){
+      r-=ADJ;
+    }else{
+      r+=ADJ;
+    }
+  }
+  return r;
+}
+
+static void line_line_adj(region_segment *A, region_segment *B,
+			  float *new_x, float *new_y, int left){
+  double newd_x;
+  double newd_y;
+
+  float Ax1=A->x1;
+  float Ay1=A->y1;
+  float Ax2=A->x2;
+  float Ay2=A->y2;
+
+  float Bx1=B->x1;
+  float By1=B->y1;
+  float Bx2=B->x2;
+  float By2=B->y2;
+
+  line_adj(&Ax1, &Ay1, &Ax2, &Ay2, left);
+  line_adj(&Bx1, &By1, &Bx2, &By2, left);
+
+  // compute new intersection
+  if(!intersects(Ax1,Ay1,Ax2,Ay2, Bx1,By1,Bx2,By2, &newd_x, &newd_y)){
+    // odd; do nothing rather than fail unpredictably
+    *new_x=Ax2;
+    *new_y=Ay2;
+  }else{
+    *new_x=newd_x;
+    *new_y=newd_y;
+  }
+}
+
+static void line_arc_adj(float x1, float y1, float x2, float y2, 
+			 float cx, float cy, float r, float arc_phi,
+			 float *new_x2, float *new_y2, int lleft, int aleft){
+  float xd = x2 - x1;
+  float yd = y2 - y1;
+  float c = tangent_distance_from_center(x1,y1,x2,y2,cx,cy);
+  float a = sqrt(r*r - c*c),a2;
+  float M = hypot(xd,yd);
+  float ax = x2 + xd/M*a;
+  float ay = y2 + yd/M*a;
+
+  float ax1 = x2 - xd/M*a;
+  float ay1 = y2 - yd/M*a;
+  if(hypot(ax1-cx,ay1-cy) < hypot(ax-cx,ay-cy)){
+    ax=ax1;
+    ay=ay1;
+  }
+  
+  xd = ax-x2;
+  yd = ay-y2;
+
+  point_adj(x1, y1, x2, y2, &ax, &ay, lleft);
+
+  r = radius_adjust(r,arc_phi,aleft);
+  c = hypot(cx-ax,cy-ay);
+  a2 = sqrt(r*r-c*c);
+
+  *new_x2 = ax - xd/a*a2; 
+  *new_y2 = ay - yd/a*a2; 
+}
+
+static void arc_arc_adj(region_segment *arc, region_segment *next,
+			 float *new_x2, float *new_y2, int left){
+  float x2 =arc->x2;
+  float y2 =arc->y2;
+
+  float cx1=arc->cx;
+  float cy1=arc->cy;
+  float r1 =arc->radius;
+
+  float cx2=next->cx;
+  float cy2=next->cy;
+  float r2 =next->radius;
+
+  float c;
+  float xd = cx2-cx1;
+  float yd = cy2-cy1;
+  float d = hypot(xd,yd);
+  float x = (d*d - r1*r1 + r2*r2) / (2*d);
+
+  // is the old x2/y2 to the left or right of the line connecting the
+  // circle centers?
+  float angle_x2y2 = line_angle(cx1,cy1,x2,y2);
+  float angle_c1c2 = line_angle(cx1,cy1,cx2,cy2);
+  float angle = angle_x2y2 - angle_c1c2;
+  if(angle < -M_PI)angle += M_PI*2.f;
+  if(angle >  M_PI)angle -= M_PI*2.f;
+
+  r1=radius_adjust(r1,arc->phi,left);
+  r2=radius_adjust(r2,arc->phi,left);
+  
+  if(r1+r2>=d){
+    // still have a valid solution
+    x = (d*d - r1*r1 + r2*r2) / (2*d);
+    c = sqrt(r2*r2 - x*x);
+
+    if(angle>0){
+      // left of c1,c2 segment
+      *new_x2 = cx1+xd/d*x + yd/d*c;
+      *new_y2 = cy1+yd/d*x - xd/d*c;
+    }else{
+      // right
+      *new_x2 = cx1+xd/d*x - yd/d*c;
+      *new_y2 = cy1+yd/d*x + xd/d*c;
+    }
+  }else{
+    // circles shrunk and no longer overlap.  
+    fprintf(stderr,"region overlap adjustment failed in arc_arc_adj; \n"
+	    "  This is an internal error that should never happen.\n");
+  }
+}
+
+static float phisub(float phi0, float phi1, float arcphi){
+  float phid = phi1-phi0;
+  if(arcphi<0){
+    if(phid>0) phid -= M_PI*2.f;
+  }else{
+    if(phid<0) phid += M_PI*2.f;
+  }
+  return phid;
+}
+
+static void radius_adj_xy(region_segment *s,float *x1,float *y1, int left){
+  float xd = *x1 - s->cx;
+  float yd = *y1 - s->cy;
+
+  float r = s->radius;
+  float new_r = radius_adjust(r,s->phi,left);
+  float delta = new_r/r;
+
+  *x1 = s->cx + xd*delta;
+  *y1 = s->cy + yd*delta;
+}
+
+static void adjust_layout(){
+  /* build adjustments from intersection region into layout region */
+  region_segment *s = r.l;
+  region_segment *endpath = 0;
+  region_segment *endpath_adj = 0;
+  float x2=-1,y2=-1;
+
+  // first, release previous layout
+  region_segment *l=layout_adj.l;
+  region_segment *le=l;
+
+  while(le && le->next)le=le->next;
+  if(le){
+    le->next=segpool;
+    segpool=l;
+  }
+  memset(&layout_adj,0,sizeof(layout_adj));
+
+  while(s){
+    float x1=0,y1=0,phi=0,radius=0;
+
+    if(s->cont){
+      if(!endpath){
+	endpath=s;
+	endpath_adj=0;
+      }
+    }
+    
+    if(s->layout){
+      if(s->layout<3){
+	
+	// the flags mark beginning and end of the path, but don't say
+	// if it's closed.
+	if(!s->cont && endpath_adj)
+	  if(endpath->x2 != s->x1 ||
+	     endpath->y2 != s->y1)
+	    endpath_adj=0;
+	
+	/* first handle the lone-circle special case */
+	if(s->x1==s->x2 && s->y1==s->y2){
+	  if(s->radius>0){
+	    if(s->layout == 1) radius= s->radius+2;
+	    if(s->layout == 2) radius= s->radius-2;
+	    x1=x2=s->x1;y1=y2=s->y1;
+	    phi=s->phi;
+	  }
+	}else{
+	  region_segment *p = 0;
+
+	  if(s->cont)
+	    p = s->next;
+	  else if(endpath_adj)
+	    p = endpath;
+
+	  if(p){
+	    if(s->radius){
+	      if(x2==-1){
+		x2=s->x2;
+		y2=s->y2;
+		radius_adj_xy(s,&x2,&y2,s->layout==1);
+	      }
+	      if(p->radius){
+		// arc - arc case
+		float phi0,phi1;
+		arc_arc_adj(p,s,&x1,&y1,s->layout==1);
+		phi0=line_angle(s->cx,s->cy,x1,y1);
+		phi1=line_angle(s->cx,s->cy,x2,y2);
+		phi=phisub(phi0,phi1,s->phi);
+	      }else{
+		// arc-line case
+		float phi0,phi1;
+		line_arc_adj(p->x1, p->y1, p->x2, p->y2, 
+			     s->cx, s->cy, s->radius, s->phi,
+			     &x1, &y1, s->layout==1, s->layout==1);
+		phi0=line_angle(s->cx,s->cy,x1,y1);
+		phi1=line_angle(s->cx,s->cy,x2,y2);
+		phi=phisub(phi0,phi1,s->phi);
+	      }
+	    }else{
+	      if(x2==-1){
+		x2=s->x2;
+		y2=s->y2;
+		point_adj(s->x1, s->y1, s->x2, s->y2, &x2, &y2, s->layout==1);
+	      }
+	      if(p->radius){
+		// line-arc case
+		line_arc_adj(s->x2, s->y2, s->x1, s->y1, 
+			     p->cx, p->cy, p->radius, p->phi,
+			     &x1, &y1, s->layout==2, s->layout==1);
+	      }else{
+		// line-line case
+		line_line_adj(p, s, &x1, &y1, s->layout==1);
+	      }
+	    }
+	  }else{
+	    x1=s->x1;
+	    y1=s->y1;
+	    x2=s->x2;
+	    y2=s->y2;
+	    if(s->radius){
+	      // lone arc case; alter radius
+	      radius_adj_xy(s,&x1,&y1,s->layout==1);
+	      radius_adj_xy(s,&x2,&y2,s->layout==1);
+	      phi=s->phi;
+	    }else{
+	      // lone line segment case; offset
+	      point_adj(s->x1, s->y1, s->x2, s->y2, &x1, &y1, s->layout==1);
+	      point_adj(s->x1, s->y1, s->x2, s->y2, &x2, &y2, s->layout==1);
+	      
+	    }
+	  }
+	}
+      }else{
+	x1=s->x1;
+	x2=s->x2;
+	y1=s->y1;
+	y2=s->y2;
+	phi=s->phi;
+	if(x1==x2 && y1==y2)
+	  radius = s->radius;
+      }
+
+      // push the region segment
+      {
+	region_segment *n=new_segment(&layout_adj,rint(x1),rint(y1),rint(x2),rint(y2));
+	n->layout=3;
+	n->cont=(s->cont || endpath_adj);
+
+	if(radius){
+	  // circle; radius variable is treated as a flag
+	  n->cx=x1;
+	  n->cy=y1;
+	  n->radius=radius;
+	  n->phi0=-M_PI;
+	  n->phi1= M_PI;
+	  n->cont=1;
+	}else if(s->radius){
+	  // arc
+	  compute_arc(n,phi);
+	}
+	if(s->cont && !endpath_adj)endpath_adj=n;	
+
+      }
+
+      if(endpath_adj && !s->cont){
+	// go back and clean up the endpath path member
+	endpath_adj->x2 = rint(x1);
+	endpath_adj->y2 = rint(y1);
+	
+	if(endpath->radius>0){
+	  endpath_adj->phi1=line_angle(endpath->cx,endpath->cy,endpath_adj->x2,endpath_adj->y2);
+	  endpath_adj->phi=phisub(endpath_adj->phi0,endpath_adj->phi1,endpath_adj->phi);
+	}
+      }
+    }
+    
+    if(!s->cont){
+      endpath_adj=0;
+      endpath=0;
+      x2=-1;
+      y2=-1;
+    }else{
+      x2=x1;
+      y2=y1;
+    }
+
+    s=s->next;
+  }
+}
+
+void region_init(){
+  // release any lines and arcs
+  region_segment *l=r.l;
+  region_segment *le=r.l;
+  region_segment *a=layout_adj.l;
+  region_segment *ae=layout_adj.l;
+
+  while(le && le->next)le=le->next;
+  while(ae && ae->next)ae=ae->next;
+    
+  if(le){
+    le->next=segpool;
+    segpool=l;
+  }
+  if(ae){
+    ae->next=segpool;
+    segpool=a;
+  }
+
+  memset(&r,0,sizeof(r));
+  memset(&layout_adj,0,sizeof(layout_adj));
+}
+
+void region_layout(graph *g){
+  // count up the total length of the region segments used in layout
+  float length=0,acc=0,ldel;
+  int num_adj=g->vertex_num;
+  region_segment *l;
+  vertex *v = g->verticies;
+
+  adjust_layout();
+
+  l = layout_adj.l;
+
+  while(l){
+    if(l->radius==0){
+      float xd=l->x2 - l->x1;
+      float yd=l->y2 - l->y1;
+      length += l->length = hypot(xd,yd);
+    }else{
+      float diam = l->radius*2.f*M_PI;
+      float del=phisub(l->phi0,l->phi1,l->phi);
+      if(l->phi<0)
+	del = -del;
+      
+      length += l->length = diam*del*(1.f/(M_PI*2.f));
+    }
+    l=l->next;
+  }
+
+  // non-contiguous beginnings sink a single point segment per
+  l = layout_adj.l;
+  while(l){
+    if(!l->cont)
+      num_adj--;
+    l=l->next;
+  }
+
+  /* perform layout segment by segment */
+  l = layout_adj.l;
+  ldel = (float)length/num_adj;
+  while(l && v){
+    int i;
+    int num_placed = l->cont ? rint((l->length-acc)/ldel) :  rint((l->length-acc)/ldel)+1;
+    float snap_del = l->cont ? l->length/num_placed : l->length/(num_placed-1);
+    float snap_acc=l->cont?snap_del:0;
+    
+    if(l->radius==0){
+      float x1 = l->x1;
+      float y1 = l->y1;
+      float x2 = l->x2;
+      float y2 = l->y2;
+      float xd=(x2-x1)/l->length;
+      float yd=(y2-y1)/l->length;
+      
+      for(i=0;v && i<num_placed;i++){
+	v->x = rint(x1+xd*snap_acc);
+	v->y = rint(y1+yd*snap_acc);
+	
+	if(snap_acc)
+	  acc+=ldel;
+	snap_acc+=snap_del;
+	v=v->next;
+      }
+    }else{
+      /* next is an arc */
+      float x = l->cx;
+      float y = l->cy;
+      float phid = phisub(l->phi0,l->phi1,l->phi);
+      
+      phid /= l->length;
+      
+      for(i=0;v && i<num_placed;i++){
+	v->x = rint( cos(l->phi0+phid*snap_acc)*(l->radius)+x);
+	v->y = rint( -sin(l->phi0+phid*snap_acc)*(l->radius)+y);
+	
+	if(snap_acc)
+	  acc+=ldel;
+	snap_acc+=snap_del;
+	v=v->next;
+      }
+    }
+    
+    acc-=l->length;  
+    l=l->next;
+  }
+}
+
+void region_circle(int x,int y, float rad, int layout){
+  region_segment *a=new_segment(&r,0,0,0,0);
+  a->cx=a->x1=a->x2=x;
+  a->cy=a->y1=a->y2=y;
+  a->radius=rad;
+  a->phi0=-M_PI;
+  a->phi1=M_PI;
+  a->phi=M_PI*2.f;
+  a->layout=layout;
+  a->cont=0; // not really necessary, just consistent
+  r.cont=0;
+}
+
+void region_new_area(int x, int y, int layout){
+  r.x=r.ox=x;
+  r.y=r.oy=y;
+  r.layout=layout;
+  r.cont=0;
+}
+
+void region_line_to(int x,int y){
+  region_line(&r,r.x,r.y,x,y);
+  r.x=x;
+  r.y=y;
+  r.cont=1;
+}
+
+void region_arc_to(int x,int y, float rad){
+  region_arc(&r,r.x,r.y,x,y,rad);
+  r.x=x;
+  r.y=y;
+  r.cont=1;
+}
+
+void region_close_line(){
+  region_line(&r,r.x,r.y,r.ox,r.oy);
+  r.x=r.ox;
+  r.y=r.oy;  
+  r.cont=0;
+}
+
+void region_close_arc(float rad){
+  region_arc(&r,r.x,r.y,r.ox,r.oy,rad);
+  r.x=r.ox;
+  r.y=r.oy;
+  r.cont=0;
+}
+ 
+int region_intersects(edge *e){
+
+  region_segment *s=r.l;
+  while(s){
+    if(s->layout<3){
+      if(s->radius!=0){
+	if(intersects_arc(e,s))return 1;
+      }else{
+	double xdummy,ydummy;
+	
+	if(intersects(e->A->x,e->A->y,e->B->x,e->B->y,
+		      s->x1,s->y1,s->x2,s->y2,
+		      &xdummy,&ydummy))return 1;
+
+      }
+    }
+    s=s->next;
+  }
+  return 0;
+}
+
+int have_region(){
+  if(r.l)return 1;
+  return 0;
+}

Added: trunk/planarity/graph_region.h
===================================================================
--- trunk/planarity/graph_region.h	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/graph_region.h	2005-10-14 12:22:47 UTC (rev 10156)
@@ -0,0 +1,37 @@
+/*
+ *
+ *  gPlanarity: 
+ *     The geeky little puzzle game with a big noodly crunch!
+ *    
+ *     gPlanarity copyright (C) 2005 Monty <monty at xiph.org>
+ *     Original Flash game by John Tantalo <john.tantalo at case.edu>
+ *     Original game concept by Mary Radcliffe
+ *
+ *  gPlanarity is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *   
+ *  gPlanarity is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *   
+ *  You should have received a copy of the GNU General Public License
+ *  along with Postfish; see the file COPYING.  If not, write to the
+ *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * 
+ */
+
+extern void region_init();
+
+extern int region_intersects(edge *e);
+extern void region_layout(graph *g);
+extern void region_circle(int x,int y, float rad, int layout);
+extern void region_new_area(int x, int y, int layout);
+extern void region_line_to(int x,int y);
+extern void region_arc_to(int x,int y, float rad);
+extern void region_close_line();
+extern void region_close_arc(float rad);
+extern int have_region();

Modified: trunk/planarity/graph_score.c
===================================================================
--- trunk/planarity/graph_score.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/graph_score.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -38,25 +38,25 @@
 		   g->intersection_mult);
 }
 
-int graphscore_get_multiplier(graph *g){
-  float obj_multiplier = 1;
+int graphscore_get_multiplier_percent(graph *g){
+  float obj_multiplier = 100;
   
   if(g->objective_lessthan)
     if(g->objective > g->active_intersections)
-      obj_multiplier += (g->objective-g->active_intersections)*g->objective_mult;
-
-  return ceil( obj_multiplier );
+      obj_multiplier +=  100.f * g->objective_mult / g->objective * (g->objective - g->active_intersections);
+  
+  return ceil(obj_multiplier);
 }
 
 int graphscore_get_score(graph *g){
-  return graphscore_get_raw_score(g)*graphscore_get_multiplier(g);
+  return graphscore_get_raw_score(g)*graphscore_get_multiplier_percent(g)/100;
 }
 
 int graphscore_get_bonus(graph *g){
-  float obj_multiplier = graphscore_get_multiplier(g);
+  int obj_multiplier = graphscore_get_multiplier_percent(g);
   
   if(get_timer()< g->original_intersections*g->intersection_mult)
-    return ceil ((g->original_intersections*g->intersection_mult-get_timer()) * obj_multiplier);
+    return ceil ((g->original_intersections*g->intersection_mult-get_timer()) * obj_multiplier / 100);
   
   return 0;
 }

Modified: trunk/planarity/main.c
===================================================================
--- trunk/planarity/main.c	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/main.c	2005-10-14 12:22:47 UTC (rev 10156)
@@ -132,7 +132,7 @@
   FcPattern *fc_pattern;
   FcBool scalable;
   
-  fc_pattern = FcNameParse(list);
+  fc_pattern = FcNameParse((unsigned char *)list);
 
   // load the system config
   FcConfigSubstitute(0, fc_pattern, FcMatchPattern);

Modified: trunk/planarity/version.h
===================================================================
--- trunk/planarity/version.h	2005-10-13 18:05:13 UTC (rev 10155)
+++ trunk/planarity/version.h	2005-10-14 12:22:47 UTC (rev 10156)
@@ -1,2 +1,2 @@
 #define VERSION "$Id$ "
-/* DO NOT EDIT: Automated versioning hack [Wed Oct  5 08:22:03 EDT 2005] */
+/* DO NOT EDIT: Automated versioning hack [Fri Oct 14 08:19:48 EDT 2005] */



More information about the commits mailing list