1*37da2899SCharles.Forsyth /***************************************************************************/ 2*37da2899SCharles.Forsyth /* */ 3*37da2899SCharles.Forsyth /* ahoptim.c */ 4*37da2899SCharles.Forsyth /* */ 5*37da2899SCharles.Forsyth /* FreeType auto hinting outline optimization (body). */ 6*37da2899SCharles.Forsyth /* */ 7*37da2899SCharles.Forsyth /* Copyright 2000-2001, 2002 Catharon Productions Inc. */ 8*37da2899SCharles.Forsyth /* Author: David Turner */ 9*37da2899SCharles.Forsyth /* */ 10*37da2899SCharles.Forsyth /* This file is part of the Catharon Typography Project and shall only */ 11*37da2899SCharles.Forsyth /* be used, modified, and distributed under the terms of the Catharon */ 12*37da2899SCharles.Forsyth /* Open Source License that should come with this file under the name */ 13*37da2899SCharles.Forsyth /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ 14*37da2899SCharles.Forsyth /* this file you indicate that you have read the license and */ 15*37da2899SCharles.Forsyth /* understand and accept it fully. */ 16*37da2899SCharles.Forsyth /* */ 17*37da2899SCharles.Forsyth /* Note that this license is compatible with the FreeType license. */ 18*37da2899SCharles.Forsyth /* */ 19*37da2899SCharles.Forsyth /***************************************************************************/ 20*37da2899SCharles.Forsyth 21*37da2899SCharles.Forsyth 22*37da2899SCharles.Forsyth /*************************************************************************/ 23*37da2899SCharles.Forsyth /* */ 24*37da2899SCharles.Forsyth /* This module is in charge of optimising the outlines produced by the */ 25*37da2899SCharles.Forsyth /* auto-hinter in direct mode. This is required at small pixel sizes in */ 26*37da2899SCharles.Forsyth /* order to ensure coherent spacing, among other things.. */ 27*37da2899SCharles.Forsyth /* */ 28*37da2899SCharles.Forsyth /* The technique used in this module is a simplified simulated */ 29*37da2899SCharles.Forsyth /* annealing. */ 30*37da2899SCharles.Forsyth /* */ 31*37da2899SCharles.Forsyth /*************************************************************************/ 32*37da2899SCharles.Forsyth 33*37da2899SCharles.Forsyth 34*37da2899SCharles.Forsyth #include <ft2build.h> 35*37da2899SCharles.Forsyth #include FT_INTERNAL_OBJECTS_H /* for FT_ALLOC_ARRAY() and FT_FREE() */ 36*37da2899SCharles.Forsyth #include "ahoptim.h" 37*37da2899SCharles.Forsyth 38*37da2899SCharles.Forsyth 39*37da2899SCharles.Forsyth /* define this macro to use brute force optimization -- this is slow, */ 40*37da2899SCharles.Forsyth /* but a good way to perfect the distortion function `by hand' through */ 41*37da2899SCharles.Forsyth /* tweaking */ 42*37da2899SCharles.Forsyth #define AH_BRUTE_FORCE 43*37da2899SCharles.Forsyth 44*37da2899SCharles.Forsyth 45*37da2899SCharles.Forsyth #define xxxAH_DEBUG_OPTIM 46*37da2899SCharles.Forsyth 47*37da2899SCharles.Forsyth 48*37da2899SCharles.Forsyth #undef LOG 49*37da2899SCharles.Forsyth #ifdef AH_DEBUG_OPTIM 50*37da2899SCharles.Forsyth 51*37da2899SCharles.Forsyth #define LOG( x ) optim_log ## x 52*37da2899SCharles.Forsyth 53*37da2899SCharles.Forsyth #else 54*37da2899SCharles.Forsyth 55*37da2899SCharles.Forsyth #define LOG( x ) 56*37da2899SCharles.Forsyth 57*37da2899SCharles.Forsyth #endif /* AH_DEBUG_OPTIM */ 58*37da2899SCharles.Forsyth 59*37da2899SCharles.Forsyth 60*37da2899SCharles.Forsyth #ifdef AH_DEBUG_OPTIM 61*37da2899SCharles.Forsyth 62*37da2899SCharles.Forsyth #include <stdarg.h> 63*37da2899SCharles.Forsyth #include <stdlib.h> 64*37da2899SCharles.Forsyth 65*37da2899SCharles.Forsyth #define FLOAT( x ) ( (float)( (x) / 64.0 ) ) 66*37da2899SCharles.Forsyth 67*37da2899SCharles.Forsyth 68*37da2899SCharles.Forsyth static void optim_log(const char * fmt,...)69*37da2899SCharles.Forsyth optim_log( const char* fmt, ... ) 70*37da2899SCharles.Forsyth { 71*37da2899SCharles.Forsyth va_list ap; 72*37da2899SCharles.Forsyth 73*37da2899SCharles.Forsyth 74*37da2899SCharles.Forsyth va_start( ap, fmt ); 75*37da2899SCharles.Forsyth vprintf( fmt, ap ); 76*37da2899SCharles.Forsyth va_end( ap ); 77*37da2899SCharles.Forsyth } 78*37da2899SCharles.Forsyth 79*37da2899SCharles.Forsyth 80*37da2899SCharles.Forsyth static void AH_Dump_Stems(AH_Optimizer * optimizer)81*37da2899SCharles.Forsyth AH_Dump_Stems( AH_Optimizer* optimizer ) 82*37da2899SCharles.Forsyth { 83*37da2899SCharles.Forsyth int n; 84*37da2899SCharles.Forsyth AH_Stem* stem; 85*37da2899SCharles.Forsyth 86*37da2899SCharles.Forsyth 87*37da2899SCharles.Forsyth stem = optimizer->stems; 88*37da2899SCharles.Forsyth for ( n = 0; n < optimizer->num_stems; n++, stem++ ) 89*37da2899SCharles.Forsyth { 90*37da2899SCharles.Forsyth LOG(( " %c%2d [%.1f:%.1f]={%.1f:%.1f}=" 91*37da2899SCharles.Forsyth "<%1.f..%1.f> force=%.1f speed=%.1f\n", 92*37da2899SCharles.Forsyth optimizer->vertical ? 'V' : 'H', n, 93*37da2899SCharles.Forsyth FLOAT( stem->edge1->opos ), FLOAT( stem->edge2->opos ), 94*37da2899SCharles.Forsyth FLOAT( stem->edge1->pos ), FLOAT( stem->edge2->pos ), 95*37da2899SCharles.Forsyth FLOAT( stem->min_pos ), FLOAT( stem->max_pos ), 96*37da2899SCharles.Forsyth FLOAT( stem->force ), FLOAT( stem->velocity ) )); 97*37da2899SCharles.Forsyth } 98*37da2899SCharles.Forsyth } 99*37da2899SCharles.Forsyth 100*37da2899SCharles.Forsyth 101*37da2899SCharles.Forsyth static void AH_Dump_Stems2(AH_Optimizer * optimizer)102*37da2899SCharles.Forsyth AH_Dump_Stems2( AH_Optimizer* optimizer ) 103*37da2899SCharles.Forsyth { 104*37da2899SCharles.Forsyth int n; 105*37da2899SCharles.Forsyth AH_Stem* stem; 106*37da2899SCharles.Forsyth 107*37da2899SCharles.Forsyth 108*37da2899SCharles.Forsyth stem = optimizer->stems; 109*37da2899SCharles.Forsyth for ( n = 0; n < optimizer->num_stems; n++, stem++ ) 110*37da2899SCharles.Forsyth { 111*37da2899SCharles.Forsyth LOG(( " %c%2d [%.1f]=<%1.f..%1.f> force=%.1f speed=%.1f\n", 112*37da2899SCharles.Forsyth optimizer->vertical ? 'V' : 'H', n, 113*37da2899SCharles.Forsyth FLOAT( stem->pos ), 114*37da2899SCharles.Forsyth FLOAT( stem->min_pos ), FLOAT( stem->max_pos ), 115*37da2899SCharles.Forsyth FLOAT( stem->force ), FLOAT( stem->velocity ) )); 116*37da2899SCharles.Forsyth } 117*37da2899SCharles.Forsyth } 118*37da2899SCharles.Forsyth 119*37da2899SCharles.Forsyth 120*37da2899SCharles.Forsyth static void AH_Dump_Springs(AH_Optimizer * optimizer)121*37da2899SCharles.Forsyth AH_Dump_Springs( AH_Optimizer* optimizer ) 122*37da2899SCharles.Forsyth { 123*37da2899SCharles.Forsyth int n; 124*37da2899SCharles.Forsyth AH_Spring* spring; 125*37da2899SCharles.Forsyth AH_Stem* stems; 126*37da2899SCharles.Forsyth 127*37da2899SCharles.Forsyth 128*37da2899SCharles.Forsyth spring = optimizer->springs; 129*37da2899SCharles.Forsyth stems = optimizer->stems; 130*37da2899SCharles.Forsyth LOG(( "%cSprings ", optimizer->vertical ? 'V' : 'H' )); 131*37da2899SCharles.Forsyth 132*37da2899SCharles.Forsyth for ( n = 0; n < optimizer->num_springs; n++, spring++ ) 133*37da2899SCharles.Forsyth { 134*37da2899SCharles.Forsyth LOG(( " [%d-%d:%.1f:%1.f:%.1f]", 135*37da2899SCharles.Forsyth spring->stem1 - stems, spring->stem2 - stems, 136*37da2899SCharles.Forsyth FLOAT( spring->owidth ), 137*37da2899SCharles.Forsyth FLOAT( spring->stem2->pos - 138*37da2899SCharles.Forsyth ( spring->stem1->pos + spring->stem1->width ) ), 139*37da2899SCharles.Forsyth FLOAT( spring->tension ) )); 140*37da2899SCharles.Forsyth } 141*37da2899SCharles.Forsyth 142*37da2899SCharles.Forsyth LOG(( "\n" )); 143*37da2899SCharles.Forsyth } 144*37da2899SCharles.Forsyth 145*37da2899SCharles.Forsyth #endif /* AH_DEBUG_OPTIM */ 146*37da2899SCharles.Forsyth 147*37da2899SCharles.Forsyth 148*37da2899SCharles.Forsyth /*************************************************************************/ 149*37da2899SCharles.Forsyth /*************************************************************************/ 150*37da2899SCharles.Forsyth /*************************************************************************/ 151*37da2899SCharles.Forsyth /**** ****/ 152*37da2899SCharles.Forsyth /**** COMPUTE STEMS AND SPRINGS IN AN OUTLINE ****/ 153*37da2899SCharles.Forsyth /**** ****/ 154*37da2899SCharles.Forsyth /*************************************************************************/ 155*37da2899SCharles.Forsyth /*************************************************************************/ 156*37da2899SCharles.Forsyth /*************************************************************************/ 157*37da2899SCharles.Forsyth 158*37da2899SCharles.Forsyth 159*37da2899SCharles.Forsyth static int valid_stem_segments(AH_Segment seg1,AH_Segment seg2)160*37da2899SCharles.Forsyth valid_stem_segments( AH_Segment seg1, 161*37da2899SCharles.Forsyth AH_Segment seg2 ) 162*37da2899SCharles.Forsyth { 163*37da2899SCharles.Forsyth return seg1->serif == 0 && 164*37da2899SCharles.Forsyth seg2 && 165*37da2899SCharles.Forsyth seg2->link == seg1 && 166*37da2899SCharles.Forsyth seg1->pos < seg2->pos && 167*37da2899SCharles.Forsyth seg1->min_coord <= seg2->max_coord && 168*37da2899SCharles.Forsyth seg2->min_coord <= seg1->max_coord; 169*37da2899SCharles.Forsyth } 170*37da2899SCharles.Forsyth 171*37da2899SCharles.Forsyth 172*37da2899SCharles.Forsyth /* compute all stems in an outline */ 173*37da2899SCharles.Forsyth static int optim_compute_stems(AH_Optimizer * optimizer)174*37da2899SCharles.Forsyth optim_compute_stems( AH_Optimizer* optimizer ) 175*37da2899SCharles.Forsyth { 176*37da2899SCharles.Forsyth AH_Outline outline = optimizer->outline; 177*37da2899SCharles.Forsyth FT_Fixed scale; 178*37da2899SCharles.Forsyth FT_Memory memory = optimizer->memory; 179*37da2899SCharles.Forsyth FT_Error error = 0; 180*37da2899SCharles.Forsyth FT_Int dimension; 181*37da2899SCharles.Forsyth AH_Edge edges; 182*37da2899SCharles.Forsyth AH_Edge edge_limit; 183*37da2899SCharles.Forsyth AH_Stem** p_stems; 184*37da2899SCharles.Forsyth FT_Int* p_num_stems; 185*37da2899SCharles.Forsyth 186*37da2899SCharles.Forsyth 187*37da2899SCharles.Forsyth edges = outline->horz_edges; 188*37da2899SCharles.Forsyth edge_limit = edges + outline->num_hedges; 189*37da2899SCharles.Forsyth scale = outline->y_scale; 190*37da2899SCharles.Forsyth 191*37da2899SCharles.Forsyth p_stems = &optimizer->horz_stems; 192*37da2899SCharles.Forsyth p_num_stems = &optimizer->num_hstems; 193*37da2899SCharles.Forsyth 194*37da2899SCharles.Forsyth for ( dimension = 1; dimension >= 0; dimension-- ) 195*37da2899SCharles.Forsyth { 196*37da2899SCharles.Forsyth AH_Stem* stems = 0; 197*37da2899SCharles.Forsyth FT_Int num_stems = 0; 198*37da2899SCharles.Forsyth AH_Edge edge; 199*37da2899SCharles.Forsyth 200*37da2899SCharles.Forsyth 201*37da2899SCharles.Forsyth /* first of all, count the number of stems in this direction */ 202*37da2899SCharles.Forsyth for ( edge = edges; edge < edge_limit; edge++ ) 203*37da2899SCharles.Forsyth { 204*37da2899SCharles.Forsyth AH_Segment seg = edge->first; 205*37da2899SCharles.Forsyth 206*37da2899SCharles.Forsyth 207*37da2899SCharles.Forsyth do 208*37da2899SCharles.Forsyth { 209*37da2899SCharles.Forsyth if (valid_stem_segments( seg, seg->link ) ) 210*37da2899SCharles.Forsyth num_stems++; 211*37da2899SCharles.Forsyth 212*37da2899SCharles.Forsyth seg = seg->edge_next; 213*37da2899SCharles.Forsyth 214*37da2899SCharles.Forsyth } while ( seg != edge->first ); 215*37da2899SCharles.Forsyth } 216*37da2899SCharles.Forsyth 217*37da2899SCharles.Forsyth /* now allocate the stems and build their table */ 218*37da2899SCharles.Forsyth if ( num_stems > 0 ) 219*37da2899SCharles.Forsyth { 220*37da2899SCharles.Forsyth AH_Stem* stem; 221*37da2899SCharles.Forsyth 222*37da2899SCharles.Forsyth 223*37da2899SCharles.Forsyth if ( FT_NEW_ARRAY( stems, num_stems ) ) 224*37da2899SCharles.Forsyth goto Exit; 225*37da2899SCharles.Forsyth 226*37da2899SCharles.Forsyth stem = stems; 227*37da2899SCharles.Forsyth for ( edge = edges; edge < edge_limit; edge++ ) 228*37da2899SCharles.Forsyth { 229*37da2899SCharles.Forsyth AH_Segment seg = edge->first; 230*37da2899SCharles.Forsyth AH_Segment seg2; 231*37da2899SCharles.Forsyth 232*37da2899SCharles.Forsyth 233*37da2899SCharles.Forsyth do 234*37da2899SCharles.Forsyth { 235*37da2899SCharles.Forsyth seg2 = seg->link; 236*37da2899SCharles.Forsyth if ( valid_stem_segments( seg, seg2 ) ) 237*37da2899SCharles.Forsyth { 238*37da2899SCharles.Forsyth AH_Edge edge1 = seg->edge; 239*37da2899SCharles.Forsyth AH_Edge edge2 = seg2->edge; 240*37da2899SCharles.Forsyth 241*37da2899SCharles.Forsyth 242*37da2899SCharles.Forsyth stem->edge1 = edge1; 243*37da2899SCharles.Forsyth stem->edge2 = edge2; 244*37da2899SCharles.Forsyth stem->opos = edge1->opos; 245*37da2899SCharles.Forsyth stem->pos = edge1->pos; 246*37da2899SCharles.Forsyth stem->owidth = edge2->opos - edge1->opos; 247*37da2899SCharles.Forsyth stem->width = edge2->pos - edge1->pos; 248*37da2899SCharles.Forsyth 249*37da2899SCharles.Forsyth /* compute min_coord and max_coord */ 250*37da2899SCharles.Forsyth { 251*37da2899SCharles.Forsyth FT_Pos min_coord = seg->min_coord; 252*37da2899SCharles.Forsyth FT_Pos max_coord = seg->max_coord; 253*37da2899SCharles.Forsyth 254*37da2899SCharles.Forsyth 255*37da2899SCharles.Forsyth if ( seg2->min_coord > min_coord ) 256*37da2899SCharles.Forsyth min_coord = seg2->min_coord; 257*37da2899SCharles.Forsyth 258*37da2899SCharles.Forsyth if ( seg2->max_coord < max_coord ) 259*37da2899SCharles.Forsyth max_coord = seg2->max_coord; 260*37da2899SCharles.Forsyth 261*37da2899SCharles.Forsyth stem->min_coord = min_coord; 262*37da2899SCharles.Forsyth stem->max_coord = max_coord; 263*37da2899SCharles.Forsyth } 264*37da2899SCharles.Forsyth 265*37da2899SCharles.Forsyth /* compute minimum and maximum positions for stem -- */ 266*37da2899SCharles.Forsyth /* note that the left-most/bottom-most stem has always */ 267*37da2899SCharles.Forsyth /* a fixed position */ 268*37da2899SCharles.Forsyth if ( stem == stems || edge1->blue_edge || edge2->blue_edge ) 269*37da2899SCharles.Forsyth { 270*37da2899SCharles.Forsyth /* this stem cannot move; it is snapped to a blue edge */ 271*37da2899SCharles.Forsyth stem->min_pos = stem->pos; 272*37da2899SCharles.Forsyth stem->max_pos = stem->pos; 273*37da2899SCharles.Forsyth } 274*37da2899SCharles.Forsyth else 275*37da2899SCharles.Forsyth { 276*37da2899SCharles.Forsyth /* this edge can move; compute its min and max positions */ 277*37da2899SCharles.Forsyth FT_Pos pos1 = stem->opos; 278*37da2899SCharles.Forsyth FT_Pos pos2 = pos1 + stem->owidth - stem->width; 279*37da2899SCharles.Forsyth FT_Pos min1 = pos1 & -64; 280*37da2899SCharles.Forsyth FT_Pos min2 = pos2 & -64; 281*37da2899SCharles.Forsyth 282*37da2899SCharles.Forsyth 283*37da2899SCharles.Forsyth stem->min_pos = min1; 284*37da2899SCharles.Forsyth stem->max_pos = min1 + 64; 285*37da2899SCharles.Forsyth if ( min2 < min1 ) 286*37da2899SCharles.Forsyth stem->min_pos = min2; 287*37da2899SCharles.Forsyth else 288*37da2899SCharles.Forsyth stem->max_pos = min2 + 64; 289*37da2899SCharles.Forsyth 290*37da2899SCharles.Forsyth /* XXX: just to see what it does */ 291*37da2899SCharles.Forsyth stem->max_pos += 64; 292*37da2899SCharles.Forsyth 293*37da2899SCharles.Forsyth /* just for the case where direct hinting did some */ 294*37da2899SCharles.Forsyth /* incredible things (e.g. blue edge shifts) */ 295*37da2899SCharles.Forsyth if ( stem->min_pos > stem->pos ) 296*37da2899SCharles.Forsyth stem->min_pos = stem->pos; 297*37da2899SCharles.Forsyth 298*37da2899SCharles.Forsyth if ( stem->max_pos < stem->pos ) 299*37da2899SCharles.Forsyth stem->max_pos = stem->pos; 300*37da2899SCharles.Forsyth } 301*37da2899SCharles.Forsyth 302*37da2899SCharles.Forsyth stem->velocity = 0; 303*37da2899SCharles.Forsyth stem->force = 0; 304*37da2899SCharles.Forsyth 305*37da2899SCharles.Forsyth stem++; 306*37da2899SCharles.Forsyth } 307*37da2899SCharles.Forsyth seg = seg->edge_next; 308*37da2899SCharles.Forsyth 309*37da2899SCharles.Forsyth } while ( seg != edge->first ); 310*37da2899SCharles.Forsyth } 311*37da2899SCharles.Forsyth } 312*37da2899SCharles.Forsyth 313*37da2899SCharles.Forsyth *p_stems = stems; 314*37da2899SCharles.Forsyth *p_num_stems = num_stems; 315*37da2899SCharles.Forsyth 316*37da2899SCharles.Forsyth edges = outline->vert_edges; 317*37da2899SCharles.Forsyth edge_limit = edges + outline->num_vedges; 318*37da2899SCharles.Forsyth scale = outline->x_scale; 319*37da2899SCharles.Forsyth 320*37da2899SCharles.Forsyth p_stems = &optimizer->vert_stems; 321*37da2899SCharles.Forsyth p_num_stems = &optimizer->num_vstems; 322*37da2899SCharles.Forsyth } 323*37da2899SCharles.Forsyth 324*37da2899SCharles.Forsyth Exit: 325*37da2899SCharles.Forsyth 326*37da2899SCharles.Forsyth #ifdef AH_DEBUG_OPTIM 327*37da2899SCharles.Forsyth AH_Dump_Stems( optimizer ); 328*37da2899SCharles.Forsyth #endif 329*37da2899SCharles.Forsyth 330*37da2899SCharles.Forsyth return error; 331*37da2899SCharles.Forsyth } 332*37da2899SCharles.Forsyth 333*37da2899SCharles.Forsyth 334*37da2899SCharles.Forsyth /* returns the spring area between two stems, 0 if none */ 335*37da2899SCharles.Forsyth static FT_Pos stem_spring_area(AH_Stem * stem1,AH_Stem * stem2)336*37da2899SCharles.Forsyth stem_spring_area( AH_Stem* stem1, 337*37da2899SCharles.Forsyth AH_Stem* stem2 ) 338*37da2899SCharles.Forsyth { 339*37da2899SCharles.Forsyth FT_Pos area1 = stem1->max_coord - stem1->min_coord; 340*37da2899SCharles.Forsyth FT_Pos area2 = stem2->max_coord - stem2->min_coord; 341*37da2899SCharles.Forsyth FT_Pos min = stem1->min_coord; 342*37da2899SCharles.Forsyth FT_Pos max = stem1->max_coord; 343*37da2899SCharles.Forsyth FT_Pos area; 344*37da2899SCharles.Forsyth 345*37da2899SCharles.Forsyth 346*37da2899SCharles.Forsyth /* order stems */ 347*37da2899SCharles.Forsyth if ( stem2->opos <= stem1->opos + stem1->owidth ) 348*37da2899SCharles.Forsyth return 0; 349*37da2899SCharles.Forsyth 350*37da2899SCharles.Forsyth if ( min < stem2->min_coord ) 351*37da2899SCharles.Forsyth min = stem2->min_coord; 352*37da2899SCharles.Forsyth 353*37da2899SCharles.Forsyth if ( max < stem2->max_coord ) 354*37da2899SCharles.Forsyth max = stem2->max_coord; 355*37da2899SCharles.Forsyth 356*37da2899SCharles.Forsyth area = ( max-min ); 357*37da2899SCharles.Forsyth if ( 2 * area < area1 && 2 * area < area2 ) 358*37da2899SCharles.Forsyth area = 0; 359*37da2899SCharles.Forsyth 360*37da2899SCharles.Forsyth return area; 361*37da2899SCharles.Forsyth } 362*37da2899SCharles.Forsyth 363*37da2899SCharles.Forsyth 364*37da2899SCharles.Forsyth /* compute all springs in an outline */ 365*37da2899SCharles.Forsyth static int optim_compute_springs(AH_Optimizer * optimizer)366*37da2899SCharles.Forsyth optim_compute_springs( AH_Optimizer* optimizer ) 367*37da2899SCharles.Forsyth { 368*37da2899SCharles.Forsyth /* basically, a spring exists between two stems if most of their */ 369*37da2899SCharles.Forsyth /* surface is aligned */ 370*37da2899SCharles.Forsyth FT_Memory memory = optimizer->memory; 371*37da2899SCharles.Forsyth 372*37da2899SCharles.Forsyth AH_Stem* stems; 373*37da2899SCharles.Forsyth AH_Stem* stem_limit; 374*37da2899SCharles.Forsyth AH_Stem* stem; 375*37da2899SCharles.Forsyth int dimension; 376*37da2899SCharles.Forsyth int error = 0; 377*37da2899SCharles.Forsyth 378*37da2899SCharles.Forsyth FT_Int* p_num_springs; 379*37da2899SCharles.Forsyth AH_Spring** p_springs; 380*37da2899SCharles.Forsyth 381*37da2899SCharles.Forsyth 382*37da2899SCharles.Forsyth stems = optimizer->horz_stems; 383*37da2899SCharles.Forsyth stem_limit = stems + optimizer->num_hstems; 384*37da2899SCharles.Forsyth 385*37da2899SCharles.Forsyth p_springs = &optimizer->horz_springs; 386*37da2899SCharles.Forsyth p_num_springs = &optimizer->num_hsprings; 387*37da2899SCharles.Forsyth 388*37da2899SCharles.Forsyth for ( dimension = 1; dimension >= 0; dimension-- ) 389*37da2899SCharles.Forsyth { 390*37da2899SCharles.Forsyth FT_Int num_springs = 0; 391*37da2899SCharles.Forsyth AH_Spring* springs = 0; 392*37da2899SCharles.Forsyth 393*37da2899SCharles.Forsyth 394*37da2899SCharles.Forsyth /* first of all, count stem springs */ 395*37da2899SCharles.Forsyth for ( stem = stems; stem + 1 < stem_limit; stem++ ) 396*37da2899SCharles.Forsyth { 397*37da2899SCharles.Forsyth AH_Stem* stem2; 398*37da2899SCharles.Forsyth 399*37da2899SCharles.Forsyth 400*37da2899SCharles.Forsyth for ( stem2 = stem+1; stem2 < stem_limit; stem2++ ) 401*37da2899SCharles.Forsyth if ( stem_spring_area( stem, stem2 ) ) 402*37da2899SCharles.Forsyth num_springs++; 403*37da2899SCharles.Forsyth } 404*37da2899SCharles.Forsyth 405*37da2899SCharles.Forsyth /* then allocate and build the springs table */ 406*37da2899SCharles.Forsyth if ( num_springs > 0 ) 407*37da2899SCharles.Forsyth { 408*37da2899SCharles.Forsyth AH_Spring* spring; 409*37da2899SCharles.Forsyth 410*37da2899SCharles.Forsyth 411*37da2899SCharles.Forsyth /* allocate table of springs */ 412*37da2899SCharles.Forsyth if ( FT_NEW_ARRAY( springs, num_springs ) ) 413*37da2899SCharles.Forsyth goto Exit; 414*37da2899SCharles.Forsyth 415*37da2899SCharles.Forsyth /* fill the springs table */ 416*37da2899SCharles.Forsyth spring = springs; 417*37da2899SCharles.Forsyth for ( stem = stems; stem+1 < stem_limit; stem++ ) 418*37da2899SCharles.Forsyth { 419*37da2899SCharles.Forsyth AH_Stem* stem2; 420*37da2899SCharles.Forsyth FT_Pos area; 421*37da2899SCharles.Forsyth 422*37da2899SCharles.Forsyth 423*37da2899SCharles.Forsyth for ( stem2 = stem + 1; stem2 < stem_limit; stem2++ ) 424*37da2899SCharles.Forsyth { 425*37da2899SCharles.Forsyth area = stem_spring_area( stem, stem2 ); 426*37da2899SCharles.Forsyth if ( area ) 427*37da2899SCharles.Forsyth { 428*37da2899SCharles.Forsyth /* add a new spring here */ 429*37da2899SCharles.Forsyth spring->stem1 = stem; 430*37da2899SCharles.Forsyth spring->stem2 = stem2; 431*37da2899SCharles.Forsyth spring->owidth = stem2->opos - ( stem->opos + stem->owidth ); 432*37da2899SCharles.Forsyth spring->tension = 0; 433*37da2899SCharles.Forsyth 434*37da2899SCharles.Forsyth spring++; 435*37da2899SCharles.Forsyth } 436*37da2899SCharles.Forsyth } 437*37da2899SCharles.Forsyth } 438*37da2899SCharles.Forsyth } 439*37da2899SCharles.Forsyth *p_num_springs = num_springs; 440*37da2899SCharles.Forsyth *p_springs = springs; 441*37da2899SCharles.Forsyth 442*37da2899SCharles.Forsyth stems = optimizer->vert_stems; 443*37da2899SCharles.Forsyth stem_limit = stems + optimizer->num_vstems; 444*37da2899SCharles.Forsyth 445*37da2899SCharles.Forsyth p_springs = &optimizer->vert_springs; 446*37da2899SCharles.Forsyth p_num_springs = &optimizer->num_vsprings; 447*37da2899SCharles.Forsyth } 448*37da2899SCharles.Forsyth 449*37da2899SCharles.Forsyth Exit: 450*37da2899SCharles.Forsyth 451*37da2899SCharles.Forsyth #ifdef AH_DEBUG_OPTIM 452*37da2899SCharles.Forsyth AH_Dump_Springs( optimizer ); 453*37da2899SCharles.Forsyth #endif 454*37da2899SCharles.Forsyth 455*37da2899SCharles.Forsyth return error; 456*37da2899SCharles.Forsyth } 457*37da2899SCharles.Forsyth 458*37da2899SCharles.Forsyth 459*37da2899SCharles.Forsyth /*************************************************************************/ 460*37da2899SCharles.Forsyth /*************************************************************************/ 461*37da2899SCharles.Forsyth /*************************************************************************/ 462*37da2899SCharles.Forsyth /**** ****/ 463*37da2899SCharles.Forsyth /**** OPTIMIZE THROUGH MY STRANGE SIMULATED ANNEALING ALGO ;-) ****/ 464*37da2899SCharles.Forsyth /**** ****/ 465*37da2899SCharles.Forsyth /*************************************************************************/ 466*37da2899SCharles.Forsyth /*************************************************************************/ 467*37da2899SCharles.Forsyth /*************************************************************************/ 468*37da2899SCharles.Forsyth 469*37da2899SCharles.Forsyth #ifndef AH_BRUTE_FORCE 470*37da2899SCharles.Forsyth 471*37da2899SCharles.Forsyth /* compute all spring tensions */ 472*37da2899SCharles.Forsyth static void optim_compute_tensions(AH_Optimizer * optimizer)473*37da2899SCharles.Forsyth optim_compute_tensions( AH_Optimizer* optimizer ) 474*37da2899SCharles.Forsyth { 475*37da2899SCharles.Forsyth AH_Spring* spring = optimizer->springs; 476*37da2899SCharles.Forsyth AH_Spring* limit = spring + optimizer->num_springs; 477*37da2899SCharles.Forsyth 478*37da2899SCharles.Forsyth 479*37da2899SCharles.Forsyth for ( ; spring < limit; spring++ ) 480*37da2899SCharles.Forsyth { 481*37da2899SCharles.Forsyth AH_Stem* stem1 = spring->stem1; 482*37da2899SCharles.Forsyth AH_Stem* stem2 = spring->stem2; 483*37da2899SCharles.Forsyth FT_Int status; 484*37da2899SCharles.Forsyth 485*37da2899SCharles.Forsyth FT_Pos width; 486*37da2899SCharles.Forsyth FT_Pos tension; 487*37da2899SCharles.Forsyth FT_Pos sign; 488*37da2899SCharles.Forsyth 489*37da2899SCharles.Forsyth 490*37da2899SCharles.Forsyth /* compute the tension; it simply is -K*(new_width-old_width) */ 491*37da2899SCharles.Forsyth width = stem2->pos - ( stem1->pos + stem1->width ); 492*37da2899SCharles.Forsyth tension = width - spring->owidth; 493*37da2899SCharles.Forsyth 494*37da2899SCharles.Forsyth sign = 1; 495*37da2899SCharles.Forsyth if ( tension < 0 ) 496*37da2899SCharles.Forsyth { 497*37da2899SCharles.Forsyth sign = -1; 498*37da2899SCharles.Forsyth tension = -tension; 499*37da2899SCharles.Forsyth } 500*37da2899SCharles.Forsyth 501*37da2899SCharles.Forsyth if ( width <= 0 ) 502*37da2899SCharles.Forsyth tension = 32000; 503*37da2899SCharles.Forsyth else 504*37da2899SCharles.Forsyth tension = ( tension << 10 ) / width; 505*37da2899SCharles.Forsyth 506*37da2899SCharles.Forsyth tension = -sign * FT_MulFix( tension, optimizer->tension_scale ); 507*37da2899SCharles.Forsyth spring->tension = tension; 508*37da2899SCharles.Forsyth 509*37da2899SCharles.Forsyth /* now, distribute tension among the englobing stems, if they */ 510*37da2899SCharles.Forsyth /* are able to move */ 511*37da2899SCharles.Forsyth status = 0; 512*37da2899SCharles.Forsyth if ( stem1->pos <= stem1->min_pos ) 513*37da2899SCharles.Forsyth status |= 1; 514*37da2899SCharles.Forsyth if ( stem2->pos >= stem2->max_pos ) 515*37da2899SCharles.Forsyth status |= 2; 516*37da2899SCharles.Forsyth 517*37da2899SCharles.Forsyth if ( !status ) 518*37da2899SCharles.Forsyth tension /= 2; 519*37da2899SCharles.Forsyth 520*37da2899SCharles.Forsyth if ( ( status & 1 ) == 0 ) 521*37da2899SCharles.Forsyth stem1->force -= tension; 522*37da2899SCharles.Forsyth 523*37da2899SCharles.Forsyth if ( ( status & 2 ) == 0 ) 524*37da2899SCharles.Forsyth stem2->force += tension; 525*37da2899SCharles.Forsyth } 526*37da2899SCharles.Forsyth } 527*37da2899SCharles.Forsyth 528*37da2899SCharles.Forsyth 529*37da2899SCharles.Forsyth /* compute all stem movements -- returns 0 if nothing moved */ 530*37da2899SCharles.Forsyth static int optim_compute_stem_movements(AH_Optimizer * optimizer)531*37da2899SCharles.Forsyth optim_compute_stem_movements( AH_Optimizer* optimizer ) 532*37da2899SCharles.Forsyth { 533*37da2899SCharles.Forsyth AH_Stem* stems = optimizer->stems; 534*37da2899SCharles.Forsyth AH_Stem* limit = stems + optimizer->num_stems; 535*37da2899SCharles.Forsyth AH_Stem* stem = stems; 536*37da2899SCharles.Forsyth int moved = 0; 537*37da2899SCharles.Forsyth 538*37da2899SCharles.Forsyth 539*37da2899SCharles.Forsyth /* set initial forces to velocity */ 540*37da2899SCharles.Forsyth for ( stem = stems; stem < limit; stem++ ) 541*37da2899SCharles.Forsyth { 542*37da2899SCharles.Forsyth stem->force = stem->velocity; 543*37da2899SCharles.Forsyth stem->velocity /= 2; /* XXX: Heuristics */ 544*37da2899SCharles.Forsyth } 545*37da2899SCharles.Forsyth 546*37da2899SCharles.Forsyth /* compute the sum of forces applied on each stem */ 547*37da2899SCharles.Forsyth optim_compute_tensions( optimizer ); 548*37da2899SCharles.Forsyth 549*37da2899SCharles.Forsyth #ifdef AH_DEBUG_OPTIM 550*37da2899SCharles.Forsyth AH_Dump_Springs( optimizer ); 551*37da2899SCharles.Forsyth AH_Dump_Stems2( optimizer ); 552*37da2899SCharles.Forsyth #endif 553*37da2899SCharles.Forsyth 554*37da2899SCharles.Forsyth /* now, see whether something can move */ 555*37da2899SCharles.Forsyth for ( stem = stems; stem < limit; stem++ ) 556*37da2899SCharles.Forsyth { 557*37da2899SCharles.Forsyth if ( stem->force > optimizer->tension_threshold ) 558*37da2899SCharles.Forsyth { 559*37da2899SCharles.Forsyth /* there is enough tension to move the stem to the right */ 560*37da2899SCharles.Forsyth if ( stem->pos < stem->max_pos ) 561*37da2899SCharles.Forsyth { 562*37da2899SCharles.Forsyth stem->pos += 64; 563*37da2899SCharles.Forsyth stem->velocity = stem->force / 2; 564*37da2899SCharles.Forsyth moved = 1; 565*37da2899SCharles.Forsyth } 566*37da2899SCharles.Forsyth else 567*37da2899SCharles.Forsyth stem->velocity = 0; 568*37da2899SCharles.Forsyth } 569*37da2899SCharles.Forsyth else if ( stem->force < optimizer->tension_threshold ) 570*37da2899SCharles.Forsyth { 571*37da2899SCharles.Forsyth /* there is enough tension to move the stem to the left */ 572*37da2899SCharles.Forsyth if ( stem->pos > stem->min_pos ) 573*37da2899SCharles.Forsyth { 574*37da2899SCharles.Forsyth stem->pos -= 64; 575*37da2899SCharles.Forsyth stem->velocity = stem->force / 2; 576*37da2899SCharles.Forsyth moved = 1; 577*37da2899SCharles.Forsyth } 578*37da2899SCharles.Forsyth else 579*37da2899SCharles.Forsyth stem->velocity = 0; 580*37da2899SCharles.Forsyth } 581*37da2899SCharles.Forsyth } 582*37da2899SCharles.Forsyth 583*37da2899SCharles.Forsyth /* return 0 if nothing moved */ 584*37da2899SCharles.Forsyth return moved; 585*37da2899SCharles.Forsyth } 586*37da2899SCharles.Forsyth 587*37da2899SCharles.Forsyth #endif /* AH_BRUTE_FORCE */ 588*37da2899SCharles.Forsyth 589*37da2899SCharles.Forsyth 590*37da2899SCharles.Forsyth /* compute current global distortion from springs */ 591*37da2899SCharles.Forsyth static FT_Pos optim_compute_distortion(AH_Optimizer * optimizer)592*37da2899SCharles.Forsyth optim_compute_distortion( AH_Optimizer* optimizer ) 593*37da2899SCharles.Forsyth { 594*37da2899SCharles.Forsyth AH_Spring* spring = optimizer->springs; 595*37da2899SCharles.Forsyth AH_Spring* limit = spring + optimizer->num_springs; 596*37da2899SCharles.Forsyth FT_Pos distortion = 0; 597*37da2899SCharles.Forsyth 598*37da2899SCharles.Forsyth 599*37da2899SCharles.Forsyth for ( ; spring < limit; spring++ ) 600*37da2899SCharles.Forsyth { 601*37da2899SCharles.Forsyth AH_Stem* stem1 = spring->stem1; 602*37da2899SCharles.Forsyth AH_Stem* stem2 = spring->stem2; 603*37da2899SCharles.Forsyth FT_Pos width; 604*37da2899SCharles.Forsyth 605*37da2899SCharles.Forsyth width = stem2->pos - ( stem1->pos + stem1->width ); 606*37da2899SCharles.Forsyth width -= spring->owidth; 607*37da2899SCharles.Forsyth if ( width < 0 ) 608*37da2899SCharles.Forsyth width = -width; 609*37da2899SCharles.Forsyth 610*37da2899SCharles.Forsyth distortion += width; 611*37da2899SCharles.Forsyth } 612*37da2899SCharles.Forsyth 613*37da2899SCharles.Forsyth return distortion; 614*37da2899SCharles.Forsyth } 615*37da2899SCharles.Forsyth 616*37da2899SCharles.Forsyth 617*37da2899SCharles.Forsyth /* record stems configuration in `best of' history */ 618*37da2899SCharles.Forsyth static void optim_record_configuration(AH_Optimizer * optimizer)619*37da2899SCharles.Forsyth optim_record_configuration( AH_Optimizer* optimizer ) 620*37da2899SCharles.Forsyth { 621*37da2899SCharles.Forsyth FT_Pos distortion; 622*37da2899SCharles.Forsyth AH_Configuration* configs = optimizer->configs; 623*37da2899SCharles.Forsyth AH_Configuration* limit = configs + optimizer->num_configs; 624*37da2899SCharles.Forsyth AH_Configuration* config; 625*37da2899SCharles.Forsyth 626*37da2899SCharles.Forsyth 627*37da2899SCharles.Forsyth distortion = optim_compute_distortion( optimizer ); 628*37da2899SCharles.Forsyth LOG(( "config distortion = %.1f ", FLOAT( distortion * 64 ) )); 629*37da2899SCharles.Forsyth 630*37da2899SCharles.Forsyth /* check that we really need to add this configuration to our */ 631*37da2899SCharles.Forsyth /* sorted history */ 632*37da2899SCharles.Forsyth if ( limit > configs && limit[-1].distortion < distortion ) 633*37da2899SCharles.Forsyth { 634*37da2899SCharles.Forsyth LOG(( "ejected\n" )); 635*37da2899SCharles.Forsyth return; 636*37da2899SCharles.Forsyth } 637*37da2899SCharles.Forsyth 638*37da2899SCharles.Forsyth /* add new configuration at the end of the table */ 639*37da2899SCharles.Forsyth { 640*37da2899SCharles.Forsyth int n; 641*37da2899SCharles.Forsyth 642*37da2899SCharles.Forsyth 643*37da2899SCharles.Forsyth config = limit; 644*37da2899SCharles.Forsyth if ( optimizer->num_configs < AH_MAX_CONFIGS ) 645*37da2899SCharles.Forsyth optimizer->num_configs++; 646*37da2899SCharles.Forsyth else 647*37da2899SCharles.Forsyth config--; 648*37da2899SCharles.Forsyth 649*37da2899SCharles.Forsyth config->distortion = distortion; 650*37da2899SCharles.Forsyth 651*37da2899SCharles.Forsyth for ( n = 0; n < optimizer->num_stems; n++ ) 652*37da2899SCharles.Forsyth config->positions[n] = optimizer->stems[n].pos; 653*37da2899SCharles.Forsyth } 654*37da2899SCharles.Forsyth 655*37da2899SCharles.Forsyth /* move the current configuration towards the front of the list */ 656*37da2899SCharles.Forsyth /* when necessary -- yes this is slow bubble sort ;-) */ 657*37da2899SCharles.Forsyth while ( config > configs && config[0].distortion < config[-1].distortion ) 658*37da2899SCharles.Forsyth { 659*37da2899SCharles.Forsyth AH_Configuration temp; 660*37da2899SCharles.Forsyth 661*37da2899SCharles.Forsyth 662*37da2899SCharles.Forsyth config--; 663*37da2899SCharles.Forsyth temp = config[0]; 664*37da2899SCharles.Forsyth config[0] = config[1]; 665*37da2899SCharles.Forsyth config[1] = temp; 666*37da2899SCharles.Forsyth } 667*37da2899SCharles.Forsyth LOG(( "recorded!\n" )); 668*37da2899SCharles.Forsyth } 669*37da2899SCharles.Forsyth 670*37da2899SCharles.Forsyth 671*37da2899SCharles.Forsyth #ifdef AH_BRUTE_FORCE 672*37da2899SCharles.Forsyth 673*37da2899SCharles.Forsyth /* optimize outline in a single direction */ 674*37da2899SCharles.Forsyth static void optim_compute(AH_Optimizer * optimizer)675*37da2899SCharles.Forsyth optim_compute( AH_Optimizer* optimizer ) 676*37da2899SCharles.Forsyth { 677*37da2899SCharles.Forsyth int n; 678*37da2899SCharles.Forsyth FT_Bool moved; 679*37da2899SCharles.Forsyth 680*37da2899SCharles.Forsyth AH_Stem* stem = optimizer->stems; 681*37da2899SCharles.Forsyth AH_Stem* limit = stem + optimizer->num_stems; 682*37da2899SCharles.Forsyth 683*37da2899SCharles.Forsyth 684*37da2899SCharles.Forsyth /* empty, exit */ 685*37da2899SCharles.Forsyth if ( stem >= limit ) 686*37da2899SCharles.Forsyth return; 687*37da2899SCharles.Forsyth 688*37da2899SCharles.Forsyth optimizer->num_configs = 0; 689*37da2899SCharles.Forsyth 690*37da2899SCharles.Forsyth stem = optimizer->stems; 691*37da2899SCharles.Forsyth for ( ; stem < limit; stem++ ) 692*37da2899SCharles.Forsyth stem->pos = stem->min_pos; 693*37da2899SCharles.Forsyth 694*37da2899SCharles.Forsyth do 695*37da2899SCharles.Forsyth { 696*37da2899SCharles.Forsyth /* record current configuration */ 697*37da2899SCharles.Forsyth optim_record_configuration( optimizer ); 698*37da2899SCharles.Forsyth 699*37da2899SCharles.Forsyth /* now change configuration */ 700*37da2899SCharles.Forsyth moved = 0; 701*37da2899SCharles.Forsyth for ( stem = optimizer->stems; stem < limit; stem++ ) 702*37da2899SCharles.Forsyth { 703*37da2899SCharles.Forsyth if ( stem->pos < stem->max_pos ) 704*37da2899SCharles.Forsyth { 705*37da2899SCharles.Forsyth stem->pos += 64; 706*37da2899SCharles.Forsyth moved = 1; 707*37da2899SCharles.Forsyth break; 708*37da2899SCharles.Forsyth } 709*37da2899SCharles.Forsyth 710*37da2899SCharles.Forsyth stem->pos = stem->min_pos; 711*37da2899SCharles.Forsyth } 712*37da2899SCharles.Forsyth } while ( moved ); 713*37da2899SCharles.Forsyth 714*37da2899SCharles.Forsyth /* now, set the best stem positions */ 715*37da2899SCharles.Forsyth for ( n = 0; n < optimizer->num_stems; n++ ) 716*37da2899SCharles.Forsyth { 717*37da2899SCharles.Forsyth AH_Stem* stem = optimizer->stems + n; 718*37da2899SCharles.Forsyth FT_Pos pos = optimizer->configs[0].positions[n]; 719*37da2899SCharles.Forsyth 720*37da2899SCharles.Forsyth 721*37da2899SCharles.Forsyth stem->edge1->pos = pos; 722*37da2899SCharles.Forsyth stem->edge2->pos = pos + stem->width; 723*37da2899SCharles.Forsyth 724*37da2899SCharles.Forsyth stem->edge1->flags |= AH_EDGE_DONE; 725*37da2899SCharles.Forsyth stem->edge2->flags |= AH_EDGE_DONE; 726*37da2899SCharles.Forsyth } 727*37da2899SCharles.Forsyth } 728*37da2899SCharles.Forsyth 729*37da2899SCharles.Forsyth #else /* AH_BRUTE_FORCE */ 730*37da2899SCharles.Forsyth 731*37da2899SCharles.Forsyth /* optimize outline in a single direction */ 732*37da2899SCharles.Forsyth static void optim_compute(AH_Optimizer * optimizer)733*37da2899SCharles.Forsyth optim_compute( AH_Optimizer* optimizer ) 734*37da2899SCharles.Forsyth { 735*37da2899SCharles.Forsyth int n, counter, counter2; 736*37da2899SCharles.Forsyth 737*37da2899SCharles.Forsyth 738*37da2899SCharles.Forsyth optimizer->num_configs = 0; 739*37da2899SCharles.Forsyth optimizer->tension_scale = 0x80000L; 740*37da2899SCharles.Forsyth optimizer->tension_threshold = 64; 741*37da2899SCharles.Forsyth 742*37da2899SCharles.Forsyth /* record initial configuration threshold */ 743*37da2899SCharles.Forsyth optim_record_configuration( optimizer ); 744*37da2899SCharles.Forsyth 745*37da2899SCharles.Forsyth counter = 0; 746*37da2899SCharles.Forsyth for ( counter2 = optimizer->num_stems*8; counter2 >= 0; counter2-- ) 747*37da2899SCharles.Forsyth { 748*37da2899SCharles.Forsyth if ( counter == 0 ) 749*37da2899SCharles.Forsyth counter = 2 * optimizer->num_stems; 750*37da2899SCharles.Forsyth 751*37da2899SCharles.Forsyth if ( !optim_compute_stem_movements( optimizer ) ) 752*37da2899SCharles.Forsyth break; 753*37da2899SCharles.Forsyth 754*37da2899SCharles.Forsyth optim_record_configuration( optimizer ); 755*37da2899SCharles.Forsyth 756*37da2899SCharles.Forsyth counter--; 757*37da2899SCharles.Forsyth if ( counter == 0 ) 758*37da2899SCharles.Forsyth optimizer->tension_scale /= 2; 759*37da2899SCharles.Forsyth } 760*37da2899SCharles.Forsyth 761*37da2899SCharles.Forsyth /* now, set the best stem positions */ 762*37da2899SCharles.Forsyth for ( n = 0; n < optimizer->num_stems; n++ ) 763*37da2899SCharles.Forsyth { 764*37da2899SCharles.Forsyth AH_Stem* stem = optimizer->stems + n; 765*37da2899SCharles.Forsyth FT_Pos pos = optimizer->configs[0].positions[n]; 766*37da2899SCharles.Forsyth 767*37da2899SCharles.Forsyth 768*37da2899SCharles.Forsyth stem->edge1->pos = pos; 769*37da2899SCharles.Forsyth stem->edge2->pos = pos + stem->width; 770*37da2899SCharles.Forsyth 771*37da2899SCharles.Forsyth stem->edge1->flags |= AH_EDGE_DONE; 772*37da2899SCharles.Forsyth stem->edge2->flags |= AH_EDGE_DONE; 773*37da2899SCharles.Forsyth } 774*37da2899SCharles.Forsyth } 775*37da2899SCharles.Forsyth 776*37da2899SCharles.Forsyth #endif /* AH_BRUTE_FORCE */ 777*37da2899SCharles.Forsyth 778*37da2899SCharles.Forsyth 779*37da2899SCharles.Forsyth /*************************************************************************/ 780*37da2899SCharles.Forsyth /*************************************************************************/ 781*37da2899SCharles.Forsyth /*************************************************************************/ 782*37da2899SCharles.Forsyth /**** ****/ 783*37da2899SCharles.Forsyth /**** HIGH-LEVEL OPTIMIZER API ****/ 784*37da2899SCharles.Forsyth /**** ****/ 785*37da2899SCharles.Forsyth /*************************************************************************/ 786*37da2899SCharles.Forsyth /*************************************************************************/ 787*37da2899SCharles.Forsyth /*************************************************************************/ 788*37da2899SCharles.Forsyth 789*37da2899SCharles.Forsyth 790*37da2899SCharles.Forsyth /* releases the optimization data */ 791*37da2899SCharles.Forsyth void AH_Optimizer_Done(AH_Optimizer * optimizer)792*37da2899SCharles.Forsyth AH_Optimizer_Done( AH_Optimizer* optimizer ) 793*37da2899SCharles.Forsyth { 794*37da2899SCharles.Forsyth if ( optimizer ) 795*37da2899SCharles.Forsyth { 796*37da2899SCharles.Forsyth FT_Memory memory = optimizer->memory; 797*37da2899SCharles.Forsyth 798*37da2899SCharles.Forsyth 799*37da2899SCharles.Forsyth FT_FREE( optimizer->horz_stems ); 800*37da2899SCharles.Forsyth FT_FREE( optimizer->vert_stems ); 801*37da2899SCharles.Forsyth FT_FREE( optimizer->horz_springs ); 802*37da2899SCharles.Forsyth FT_FREE( optimizer->vert_springs ); 803*37da2899SCharles.Forsyth FT_FREE( optimizer->positions ); 804*37da2899SCharles.Forsyth } 805*37da2899SCharles.Forsyth } 806*37da2899SCharles.Forsyth 807*37da2899SCharles.Forsyth 808*37da2899SCharles.Forsyth /* loads the outline into the optimizer */ 809*37da2899SCharles.Forsyth int AH_Optimizer_Init(AH_Optimizer * optimizer,AH_Outline outline,FT_Memory memory)810*37da2899SCharles.Forsyth AH_Optimizer_Init( AH_Optimizer* optimizer, 811*37da2899SCharles.Forsyth AH_Outline outline, 812*37da2899SCharles.Forsyth FT_Memory memory ) 813*37da2899SCharles.Forsyth { 814*37da2899SCharles.Forsyth FT_Error error; 815*37da2899SCharles.Forsyth 816*37da2899SCharles.Forsyth 817*37da2899SCharles.Forsyth FT_MEM_ZERO( optimizer, sizeof ( *optimizer ) ); 818*37da2899SCharles.Forsyth optimizer->outline = outline; 819*37da2899SCharles.Forsyth optimizer->memory = memory; 820*37da2899SCharles.Forsyth 821*37da2899SCharles.Forsyth LOG(( "initializing new optimizer\n" )); 822*37da2899SCharles.Forsyth /* compute stems and springs */ 823*37da2899SCharles.Forsyth error = optim_compute_stems ( optimizer ) || 824*37da2899SCharles.Forsyth optim_compute_springs( optimizer ); 825*37da2899SCharles.Forsyth if ( error ) 826*37da2899SCharles.Forsyth goto Fail; 827*37da2899SCharles.Forsyth 828*37da2899SCharles.Forsyth /* allocate stem positions history and configurations */ 829*37da2899SCharles.Forsyth { 830*37da2899SCharles.Forsyth int n, max_stems; 831*37da2899SCharles.Forsyth 832*37da2899SCharles.Forsyth 833*37da2899SCharles.Forsyth max_stems = optimizer->num_hstems; 834*37da2899SCharles.Forsyth if ( max_stems < optimizer->num_vstems ) 835*37da2899SCharles.Forsyth max_stems = optimizer->num_vstems; 836*37da2899SCharles.Forsyth 837*37da2899SCharles.Forsyth if ( FT_NEW_ARRAY( optimizer->positions, max_stems * AH_MAX_CONFIGS ) ) 838*37da2899SCharles.Forsyth goto Fail; 839*37da2899SCharles.Forsyth 840*37da2899SCharles.Forsyth optimizer->num_configs = 0; 841*37da2899SCharles.Forsyth for ( n = 0; n < AH_MAX_CONFIGS; n++ ) 842*37da2899SCharles.Forsyth optimizer->configs[n].positions = optimizer->positions + 843*37da2899SCharles.Forsyth n * max_stems; 844*37da2899SCharles.Forsyth } 845*37da2899SCharles.Forsyth 846*37da2899SCharles.Forsyth return error; 847*37da2899SCharles.Forsyth 848*37da2899SCharles.Forsyth Fail: 849*37da2899SCharles.Forsyth AH_Optimizer_Done( optimizer ); 850*37da2899SCharles.Forsyth return error; 851*37da2899SCharles.Forsyth } 852*37da2899SCharles.Forsyth 853*37da2899SCharles.Forsyth 854*37da2899SCharles.Forsyth /* compute optimal outline */ 855*37da2899SCharles.Forsyth void AH_Optimizer_Compute(AH_Optimizer * optimizer)856*37da2899SCharles.Forsyth AH_Optimizer_Compute( AH_Optimizer* optimizer ) 857*37da2899SCharles.Forsyth { 858*37da2899SCharles.Forsyth optimizer->num_stems = optimizer->num_hstems; 859*37da2899SCharles.Forsyth optimizer->stems = optimizer->horz_stems; 860*37da2899SCharles.Forsyth optimizer->num_springs = optimizer->num_hsprings; 861*37da2899SCharles.Forsyth optimizer->springs = optimizer->horz_springs; 862*37da2899SCharles.Forsyth 863*37da2899SCharles.Forsyth if ( optimizer->num_springs > 0 ) 864*37da2899SCharles.Forsyth { 865*37da2899SCharles.Forsyth LOG(( "horizontal optimization ------------------------\n" )); 866*37da2899SCharles.Forsyth optim_compute( optimizer ); 867*37da2899SCharles.Forsyth } 868*37da2899SCharles.Forsyth 869*37da2899SCharles.Forsyth optimizer->num_stems = optimizer->num_vstems; 870*37da2899SCharles.Forsyth optimizer->stems = optimizer->vert_stems; 871*37da2899SCharles.Forsyth optimizer->num_springs = optimizer->num_vsprings; 872*37da2899SCharles.Forsyth optimizer->springs = optimizer->vert_springs; 873*37da2899SCharles.Forsyth 874*37da2899SCharles.Forsyth if ( optimizer->num_springs ) 875*37da2899SCharles.Forsyth { 876*37da2899SCharles.Forsyth LOG(( "vertical optimization --------------------------\n" )); 877*37da2899SCharles.Forsyth optim_compute( optimizer ); 878*37da2899SCharles.Forsyth } 879*37da2899SCharles.Forsyth } 880*37da2899SCharles.Forsyth 881*37da2899SCharles.Forsyth 882*37da2899SCharles.Forsyth /* END */ 883