mi_arc.c 121 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108
  1. /* This file is part of the GNU libxmi package.
  2. Copyright (C) 1985, 1986, 1987, 1988, 1989, X Consortium. For an
  3. associated permission notice, see the accompanying file README-X.
  4. GNU enhancements Copyright (C) 1998, 1999, 2000, 2005, Free Software
  5. Foundation, Inc.
  6. The GNU libxmi package is free software. You may redistribute it
  7. and/or modify it under the terms of the GNU General Public License as
  8. published by the Free Software foundation; either version 2, or (at your
  9. option) any later version.
  10. The GNU libxmi package is distributed in the hope that it will be
  11. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. General Public License for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with the GNU plotutils package; see the file COPYING. If not, write to
  16. the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
  17. Boston, MA 02110-1301, USA. */
  18. #include "sys-defines.h"
  19. #include "extern.h"
  20. /* Authors: Keith Packard and Bob Scheifler, mid to late 1980s.
  21. Hacked by Robert S. Maier <rsm@math.arizona.edu>, 1998-2000. */
  22. /* This module exports the miPolyArc() function and its reentrant
  23. counterpart miPolyArc_r. They scan-convert wide polyarcs, either solid
  24. or dashed. A polyarc is a list of arcs, which may or may not be
  25. contiguous. Here, an `arc' is an elliptic arc, i.e., a segment of an
  26. ellipse. The principal axes of the ellipse must be aligned with the
  27. coordinate axes.
  28. Each arc is drawn with a circular brush, of width equal to the line
  29. width. All pixels within the brushed area are painted.
  30. All painting goes through the low-level fillSpans() function and the
  31. MI_PAINT_SPANS() macro that it invokes, except that the miFillSppPoly()
  32. routine in mi_fplycon.c is used to paint polygonal arc caps and arc
  33. joins, if any. That routine, in turn, invokes MI_PAINT_SPANS(). */
  34. /* Warning: this code is toxic, do not dally very long here. */
  35. #include "xmi.h"
  36. #include "mi_spans.h"
  37. #include "mi_gc.h"
  38. #include "mi_api.h"
  39. #include "mi_arc.h"
  40. #include "mi_fply.h" /* for miFillSppPoly() */
  41. #include "mi_fllarc.h" /* for MIWIDEARCSETUP, MIFILLINARCSTEP etc. */
  42. /* undefine if cbrt(), a fast cube root function for non-negative
  43. arguments, is available */
  44. #define cbrt(x) pow((x), 1.0/3.0)
  45. /* undefine if hypot is available (it's X_OPEN, but not ANSI or POSIX) */
  46. #define hypot(x, y) sqrt((x)*(x) + (y)*(y))
  47. /**********************************************************************/
  48. /* To facilitate speedy drawing of elliptic arcs, we cache scan-converted
  49. wide ellipses so that we can retrieve them later, by keying on ellipse
  50. width, ellipse height, and line width. Any such cache is an
  51. miEllipseCache object; equivalently, a lib_miEllipseCache structure,
  52. which is basically an array of (cachedEllipse *)'s. Each cachedEllipse
  53. is a record, the `value' field of which is an (miArcSpanData *),
  54. i.e. basically a list of spans, computed and returned by
  55. miComputeWideEllipse().
  56. The currently used miEllipseCache structure is accessed via the
  57. ellipseCache argument of miPolyArc_r(). */
  58. /* one or two spans (any rasterized ellipse contains a list of these,
  59. indexed by y) */
  60. typedef struct
  61. {
  62. int lx, rx; /* starting points of left, right spans */
  63. int lw, rw; /* widths of left, right spans */
  64. } miArcSpan;
  65. /* `Value' part of each cache record, storing a rasterized ellipse. A
  66. rasterized ellipse is a list of ArcSpans, extending in order from the
  67. top of the ellipse down to and including the centerline, if present. It
  68. consists primarily of count1 single-occupied ArcSpans (containing only a
  69. single span), followed by count2 doubly-occupied ArcSpans (containing
  70. two spans).
  71. In all, the list contains (top ? 1 : 0) + count1 + count2 + (bot ? 1 : 0)
  72. ArcSpans. The x-coordinates (lx,rx) in the ArcSpans are relative
  73. to x = xorg = xorg_arc + width_arc/2, i.e. halfway across the ellipse.
  74. The count1 single-occupied ArcSpans are drawn downward (i.e. at
  75. successively increasing values of y), beginning at
  76. y = yorgu = yorg_arc + height_arc/2 - k, and also upward beginning at
  77. y = yorgl = yorg_arc + height_arc/2 + k.
  78. They are followed by the count2 doubly occupied ArcSpans.
  79. (Here k = height_arc/2 + (linewidth-1)/2, always.)
  80. If top=true (which is the case iff width_arc is even and linewidth is
  81. even), the first ArcSpan in the array is bogus, and should be replaced
  82. by a single pixel at x=xorg, y = yorgu-1. If bot=true, which is the
  83. case iff height_arc is even, then the ellipse must be completed by
  84. drawing the 2 or 1 spans contained in the final ArcSpan of the array on
  85. the vertical centerline. (rw<0 is a signal that this ArcSpan atypically
  86. contains only a single span.)
  87. `hole' is a kludge flag. If it is set, then after the count1 singly
  88. occupied ArcSpans are drawn upward, a single additional pixel must be
  89. drawn at (xorg,y), where y is the current (updated, i.e. decremented)
  90. value of y. y is not further decremented before the drawing of the
  91. count2 doubly occupied ArcSpans begins. */
  92. typedef struct
  93. {
  94. int k; /* height/2 + (linewidth-1)/2, always */
  95. miArcSpan *spans; /* array of up to k+2 miArcSpan structures */
  96. bool top; /* have initial (bogus) ArcSpan? */
  97. int count1; /* number of single-occupancy ArcSpans */
  98. int count2; /* number of double-occupancy ArcSpans */
  99. bool bot; /* have final (special) ArcSpan? */
  100. bool hole; /* add a certain pixel when drawing? */
  101. } miArcSpanData;
  102. /* Cache record type (key/value); key consists of width,height,linewidth.
  103. Also includes a timestamp. */
  104. typedef struct
  105. {
  106. unsigned long lrustamp; /* timestamp (time of most recent retrieval) */
  107. unsigned int width, height; /* ellipse width, height */
  108. unsigned int lw; /* line width used when rasterizing */
  109. miArcSpanData *spdata; /* `value' part of record */
  110. } cachedEllipse;
  111. /* The cache of scan-converted ellipses, including continually updated
  112. timestamp. */
  113. struct lib_miEllipseCache
  114. {
  115. cachedEllipse *ellipses; /* beginning of array of records */
  116. int size; /* number of records in array */
  117. cachedEllipse *lastCacheHit; /* pointer to last-accessed record */
  118. unsigned long lrustamp; /* clock, for timestamping records */
  119. };
  120. /* Size of cache (i.e. number of (cachedEllipse *)'s the array contains) */
  121. #define ELLIPSECACHE_SIZE 25
  122. /* Maximum height an ellipse can have, for its spans to be stored in
  123. the cache. */
  124. #define MAX_CACHEABLE_ELLIPSE_HEIGHT 1500
  125. #ifndef NO_NONREENTRANT_POLYARC_SUPPORT
  126. /* An in-library cache, used by the non-reentrant functions miPolyArc()
  127. and miZeroPolyArc(). */
  128. miEllipseCache *_mi_ellipseCache = (miEllipseCache *)NULL;
  129. #endif /* NO_NONREENTRANT_POLYARC_SUPPORT */
  130. /**********************************************************************/
  131. /* We must scan-convert poly-arcs, which consist of one or more wide
  132. elliptic arcs, which may or may not be contiguous, and which may or may
  133. not be dashed. In this, the function miComputeArcs() plays a key role.
  134. It doesn't do scan conversion. Instead, it chops an ellipse into arcs
  135. or small arcs representing dashes, determines whether joins or caps are
  136. called for, etc. What it returns is a list of miPolyArcs structures,
  137. indexed by paint type.
  138. A miPolyArcs structure comprises a list of miArcData structs, a list of
  139. joins, and a list of caps. */
  140. /* Note that self intersecting arcs (i.e. those spanning 360 degrees) never
  141. join with other arcs, and are drawn without caps (unless on/off dashed,
  142. in which case each dash segment is capped, except when the last segment
  143. meets the first segment, when no caps are drawn). */
  144. #define RIGHT_END 0
  145. #define LEFT_END 1
  146. typedef struct
  147. {
  148. int arcIndex0, arcIndex1; /* arcs to either side of the join */
  149. int paintType0, paintType1; /* their paint types */
  150. int end0, end1; /* either RIGHT_END or LEFT_END */
  151. } miArcJoinStruct;
  152. typedef struct
  153. {
  154. int arcIndex; /* arc to be capped */
  155. int end; /* either RIGHT_END or LEFT_END */
  156. } miArcCapStruct;
  157. typedef struct
  158. {
  159. SppPoint clock;
  160. SppPoint center;
  161. SppPoint counterClock;
  162. } miArcFace;
  163. typedef struct
  164. {
  165. miArc arc;
  166. bool render; /* directive to render this arc (and
  167. all previously non-rendered ones) */
  168. int join; /* related join */
  169. int cap; /* related cap */
  170. bool selfJoin; /* arc is self-joining? */
  171. miArcFace bounds[2]; /* left face and right face (3 points each) */
  172. double x0, y0; /* starting point (sub-pixel placement) */
  173. double x1, y1; /* end point (sub-pixel placement) */
  174. } miArcData;
  175. /*
  176. * The miPolyArcs struct. This is a sequence of arcs (e.g., dashes),
  177. * computed and categorized according to operation. miComputeArcs()
  178. * returns a list of these, indexed by paint type. */
  179. typedef struct
  180. {
  181. miArcData *arcs;
  182. int narcs;
  183. int arcSize; /* number of slots allocated */
  184. miArcCapStruct *caps;
  185. int ncaps;
  186. int capSize; /* number of slots allocated */
  187. miArcJoinStruct *joins;
  188. int njoins;
  189. int joinSize; /* number of slots allocated */
  190. } miPolyArcs;
  191. /**********************************************************************/
  192. /* In a sub-module below, with public functions initAccumSpans(),
  193. newFinalSpan(), and fillSpans(), we initialize an miAccumSpans
  194. structure, add spans to it, and finally paint and deallocate them.
  195. The miAccumSpans struct includes an array, indexed by y-value, each
  196. element of which is a list of spans. The y range, i.e. the range of the
  197. index variable of the array, is expanded as needed.
  198. To facilitate rapid addition of spans to the structure, we maintain as
  199. part of the miAccumSpans structure a list of unused span structures,
  200. previously allocated in "chunks". */
  201. struct finalSpan
  202. {
  203. int min, max; /* x values */
  204. struct finalSpan *next; /* pointer to next span at this value of y */
  205. };
  206. #define SPAN_CHUNK_SIZE 128 /* spans are malloc'd in chunks of this size */
  207. struct finalSpanChunk
  208. {
  209. struct finalSpan data[SPAN_CHUNK_SIZE];
  210. struct finalSpanChunk *next; /* pointer to previously malloc'd chunk */
  211. };
  212. typedef struct
  213. {
  214. struct finalSpan **finalSpans; /* array, indexed by y - finalMiny */
  215. int finalMiny, finalMaxy; /* y range */
  216. int finalSize;
  217. int nspans; /* total number of spans, not just y coors */
  218. struct finalSpanChunk *chunks; /* head of chunk list */
  219. struct finalSpan *freeFinalSpans; /* next free span in chunk at list head */
  220. } miAccumSpans;
  221. /**********************************************************************/
  222. /* Structure used by a sub-module that computes arc lengths via a polygonal
  223. approximation to the arc. The sub-module's external functions are
  224. computeDashMap() and computeAngleFromPath(). */
  225. #define DASH_MAP_SIZE 91
  226. typedef struct
  227. {
  228. double map[DASH_MAP_SIZE];
  229. } dashMap;
  230. /**********************************************************************/
  231. /* internal functions that do painting of pixels */
  232. static void fillSpans (miPaintedSet *paintedSet, miPixel pixel, miAccumSpans *accumSpans);
  233. static void miArcCap (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArcFace *pFace, int end, int xOrg, int yOrg, double xFtrans, double yFtrans);
  234. static void miArcJoin (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArcFace *pLeft, const miArcFace *pRight, int xOrgLeft, int yOrgLeft, double xFtransLeft, double yFtransLeft, int xOrgRight, int yOrgRight, double xFtransRight, double yFtransRight);
  235. static void miFillWideEllipse (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArc *parc, miEllipseCache *ellipseCache);
  236. static void miRoundCap (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, SppPoint pCenter, SppPoint pEnd, SppPoint pCorner, SppPoint pOtherCorner, int fLineEnd, int xOrg, int yOrg, double xFtrans, double yFtrans);
  237. /* internal functions that don't do painting of pixels */
  238. static double angleBetween (SppPoint center, SppPoint point1, SppPoint point2);
  239. static double miDasin (double v);
  240. static double miDatan2 (double dy, double dx);
  241. static double miDcos (double a);
  242. static double miDsin (double a);
  243. static int computeAngleFromPath (int startAngle, int endAngle, const dashMap *map, int *lenp, bool backwards);
  244. static int miGetArcPts (const SppArc *parc, int cpt, SppPoint **ppPts);
  245. static miArcData * addArc (miPolyArcs *polyArcs, const miArc *xarc);
  246. static miArcSpanData * miComputeWideEllipse (unsigned int lw, const miArc *parc, bool *mustFree, miEllipseCache *ellipseCache);
  247. static miPolyArcs * miComputeArcs (const miGC *pGC, const miArc *parcs, int narcs);
  248. static void addCap (miPolyArcs *polyArcs, int end, int arcIndex);
  249. static void addJoin (miPolyArcs *polyArcs, int end0, int index0, int paintType0, int end1, int index1, int paintType1);
  250. static void computeDashMap (const miArc *arcp, dashMap *map);
  251. static void drawArc (miAccumSpans *accumSpans, const miArc *tarc, unsigned int l, int a0, int a1, miArcFace *right, miArcFace *left, miEllipseCache *ellipseCache);
  252. static void drawZeroArc (miAccumSpans *accumSpans, const miArc *tarc, unsigned int lw, miArcFace *left, miArcFace *right);
  253. static void initAccumSpans (miAccumSpans *accumSpans);
  254. static void miArcSegment (const miGC *pGC, miAccumSpans *accumSpans, miArc tarc, miArcFace *right, miArcFace *left, miEllipseCache *ellipseCache);
  255. static void miComputeCircleSpans (unsigned int lw, const miArc *parc, miArcSpanData *spdata);
  256. static void miComputeEllipseSpans (unsigned int lw, const miArc *parc, miArcSpanData *spdata);
  257. static void miFreeArcs (const miGC *pGC, miPolyArcs *arcs);
  258. static void translateBounds (miArcFace *b, int x, int y, double fx, double fy);
  259. /*
  260. * Comments on overall miPolyArc/miPolyArc_r strategy:
  261. *
  262. * If the arc is zero width and solid, we don't worry about the join style.
  263. * To scan-convert wide solid circles, we use a fast integer algorithm. To
  264. * scan-convert wide solid ellipses, we use special case floating point
  265. * code.
  266. *
  267. * The scan-conversion of wide circles and ellipse is comparatively
  268. * trivial, though the latter involves some polynomial algebra. The
  269. * greater part of the code deals with chopping circles and ellipses,
  270. * rasterized or not, into segments. This includes dashing.
  271. *
  272. * This function is the reentrant version, miPolyArc_r. The non-reentrant
  273. * version, miPolyArc, maintains its own `rasterized ellipse' cache as
  274. * static data, and simply calls this one. */
  275. /* ARGS: ellipseCache = pointer to ellipse data cache */
  276. void
  277. miPolyArc_r (miPaintedSet *paintedSet, const miGC *pGC, int narcs, const miArc *parcs, miEllipseCache *ellipseCache)
  278. {
  279. int i;
  280. const miArc *parc;
  281. int width;
  282. miPixel pixel;
  283. miPolyArcs *polyArcs;
  284. int *cap, *join;
  285. int paintType;
  286. miAccumSpans accumSpans_struct; /* in-core accumulation of spans */
  287. /* ensure we have >=1 arcs */
  288. if (narcs <= 0)
  289. return;
  290. /* Initialize miAccumSpans structure (painted to by the low-level drawArc
  291. function). N.B. After drawArc() is repeatedly called to fill up the
  292. miAccumSpans struct with spans of a single paint type, fillSpans() is
  293. called with the desired paint type as one of its arguments. It will
  294. `paint' from the miAccumSpans struct to the miPaintedSet. */
  295. initAccumSpans (&accumSpans_struct);
  296. pixel = pGC->pixels[1]; /* default single pixel color to use */
  297. width = pGC->lineWidth;
  298. if (width == 0 && pGC->lineStyle == (int)MI_LINE_SOLID)
  299. /* zero-width solid arcs, only */
  300. {
  301. for (i = narcs, parc = parcs; --i >= 0; parc++)
  302. /* Draw zero-width arc segment to the miAccumSpans struct, as a set
  303. of spans, by invoking the low-level drawArc() function. This
  304. updates the ellipse span data cache. */
  305. miArcSegment (pGC,
  306. &accumSpans_struct, *parc,
  307. (miArcFace *)NULL, (miArcFace *)NULL,
  308. ellipseCache);
  309. /* `paint' the arc segments in the miAccumSpans struct (i.e. add them
  310. to the miPaintedSet struct), in the current pixel color */
  311. fillSpans (paintedSet, pixel, &accumSpans_struct);
  312. }
  313. else /* nonzero width, or dashing */
  314. {
  315. if ((pGC->lineStyle == (int)MI_LINE_SOLID) && narcs)
  316. {
  317. /* first, paint any initial complete ellipses (for speed) */
  318. while (parcs->width && parcs->height
  319. && (parcs->angle2 >= FULLCIRCLE ||
  320. parcs->angle2 <= -FULLCIRCLE))
  321. {
  322. /* paint complete ellipse without going through the
  323. miAccumSpans struct, also update ellipse span data cache */
  324. miFillWideEllipse (paintedSet, pixel, pGC,
  325. parcs, ellipseCache);
  326. if (--narcs == 0)
  327. return;
  328. parcs++;
  329. }
  330. }
  331. /* have one or more elliptic arcs that are incomplete ellipses
  332. (possibly dashed, possibly contiguous) to draw */
  333. /* compute arc segments (i.e. dashes) in the incomplete ellipses,
  334. indexed by color; will need to be freed with miFreeArcs() */
  335. polyArcs = miComputeArcs (pGC, parcs, narcs);
  336. cap = (int *) mi_xmalloc (pGC->numPixels * sizeof(int));
  337. join = (int *) mi_xmalloc (pGC->numPixels * sizeof(int));
  338. for (i = 0; i < pGC->numPixels; i++)
  339. cap[i] = join[i] = 0;
  340. /* iterate over colors, drawing arc segments in each color */
  341. for (paintType = 0; paintType < pGC->numPixels; paintType++)
  342. {
  343. pixel = pGC->pixels[paintType];
  344. for (i = 0; i < polyArcs[paintType].narcs; i++)
  345. {
  346. miArcData *arcData;
  347. /* Draw an arc segment to the miAccumSpans struct, via
  348. drawArc() */
  349. arcData = &polyArcs[paintType].arcs[i];
  350. miArcSegment (pGC,
  351. &accumSpans_struct, arcData->arc,
  352. &arcData->bounds[RIGHT_END],
  353. &arcData->bounds[LEFT_END],
  354. ellipseCache);
  355. if (polyArcs[paintType].arcs[i].render)
  356. {
  357. /* `paint' the arc, and any arcs previously drawn to
  358. the miAccumSpans struct but not painted, to the
  359. miPaintedSet struct, in the current pixel color */
  360. fillSpans (paintedSet, pixel, &accumSpans_struct);
  361. /* `paint' all undrawn caps to the miPaintedSet struct */
  362. /* test for self-joining arcs (won't be capped) */
  363. if (polyArcs[paintType].arcs[i].selfJoin
  364. && cap[paintType] < polyArcs[paintType].arcs[i].cap)
  365. cap[paintType]++;
  366. while (cap[paintType] < polyArcs[paintType].arcs[i].cap)
  367. {
  368. int arcIndex, end;
  369. miArcData *arcData0;
  370. arcIndex = polyArcs[paintType].caps[cap[paintType]].arcIndex;
  371. end = polyArcs[paintType].caps[cap[paintType]].end;
  372. arcData0 = &polyArcs[paintType].arcs[arcIndex];
  373. /* `paint' cap to the miPaintedSet struct by invoking
  374. miFillSppPoly() */
  375. miArcCap (paintedSet, pixel, pGC,
  376. &arcData0->bounds[end], end,
  377. arcData0->arc.x, arcData0->arc.y,
  378. (double)(0.5 * arcData0->arc.width),
  379. (double)(0.5 * arcData0->arc.height));
  380. ++cap[paintType];
  381. }
  382. /* `paint' all undrawn joins to the miPaintedSet struct */
  383. while (join[paintType] < polyArcs[paintType].arcs[i].join)
  384. {
  385. int arcIndex0, arcIndex1, end0, end1;
  386. int paintType0, paintType1;
  387. miArcData *arcData0, *arcData1;
  388. miArcJoinStruct *joinp;
  389. joinp = &polyArcs[paintType].joins[join[paintType]];
  390. arcIndex0 = joinp->arcIndex0;
  391. end0 = joinp->end0;
  392. arcIndex1 = joinp->arcIndex1;
  393. end1 = joinp->end1;
  394. paintType0 = joinp->paintType0;
  395. paintType1 = joinp->paintType1;
  396. arcData0 = &polyArcs[paintType0].arcs[arcIndex0];
  397. arcData1 = &polyArcs[paintType1].arcs[arcIndex1];
  398. /* `paint' join to the miPaintedSet struct by invoking
  399. miFillSppPoly() */
  400. miArcJoin (paintedSet, pixel, pGC,
  401. &arcData0->bounds[end0],
  402. &arcData1->bounds[end1],
  403. arcData0->arc.x, arcData0->arc.y,
  404. (double) (0.5 * arcData0->arc.width),
  405. (double) (0.5 * arcData0->arc.height),
  406. arcData1->arc.x, arcData1->arc.y,
  407. (double) (0.5 * arcData1->arc.width),
  408. (double) (0.5 * arcData1->arc.height));
  409. ++join[paintType];
  410. }
  411. }
  412. }
  413. }
  414. free (cap);
  415. free (join);
  416. /* free arc segments computed by miComputeArcs() */
  417. miFreeArcs (pGC, polyArcs);
  418. }
  419. }
  420. #ifndef NO_NONREENTRANT_POLYARC_SUPPORT
  421. /* The non-reentrant version of miPolyArc, which unlike miPolyArc_r
  422. maintains its own ellipse spans cache as static (persistent) data. */
  423. void
  424. miPolyArc (miPaintedSet *paintedSet, const miGC *pGC, int narcs, const miArc *parcs)
  425. {
  426. if (_mi_ellipseCache == (miEllipseCache *)NULL)
  427. _mi_ellipseCache = miNewEllipseCache ();
  428. miPolyArc_r (paintedSet, pGC, narcs, parcs, _mi_ellipseCache);
  429. }
  430. #endif /* not NO_NONREENTRANT_POLYARC_SUPPORT */
  431. /* Initialize a cache of rasterized elliptic arcs. (A pointer to such an
  432. object is passed to miPolyArc_r.) Such a cache comprises an array of
  433. records (i.e. cachedEllipse's), a pointer to one of them (the most
  434. recently used), and a timestamp variable that is incremented when any
  435. record is cached. `Replace least recently used' is the policy. */
  436. miEllipseCache *
  437. miNewEllipseCache (void)
  438. {
  439. int k;
  440. cachedEllipse *chead, *cent;
  441. miEllipseCache *ellipseCache;
  442. ellipseCache = (miEllipseCache *)mi_xmalloc (sizeof(miEllipseCache));
  443. /* pointer to beginning of array of records */
  444. ellipseCache->ellipses = (cachedEllipse *)mi_xmalloc (ELLIPSECACHE_SIZE * sizeof(cachedEllipse));
  445. /* length of array */
  446. ellipseCache->size = ELLIPSECACHE_SIZE;
  447. /* pointer to beginning of last-accessed record (a dummy value) */
  448. ellipseCache->lastCacheHit = ellipseCache->ellipses;
  449. /* clock for timestamping */
  450. ellipseCache->lrustamp = 0;
  451. /* initialize elements of each record with null/bogus values */
  452. chead = ellipseCache->ellipses;
  453. for (k = ELLIPSECACHE_SIZE, cent = chead; --k >= 0; cent++)
  454. {
  455. cent->lrustamp = 0;
  456. cent->lw = 0;
  457. cent->width = cent->height = 0;
  458. cent->spdata = (miArcSpanData *)NULL;
  459. }
  460. return ellipseCache;
  461. }
  462. /* Free a cache of rasterized ellipses, which must previously have been
  463. allocated by invoking miNewEllipseCache. */
  464. void
  465. miDeleteEllipseCache (miEllipseCache *ellipseCache)
  466. {
  467. int k, cache_size;
  468. cachedEllipse *chead, *cent;
  469. /* free span data in all records */
  470. chead = ellipseCache->ellipses;
  471. cache_size = ellipseCache->size;
  472. for (k = cache_size, cent = chead; --k >= 0; cent++)
  473. {
  474. miArcSpanData *spdata;
  475. spdata = cent->spdata;
  476. if (spdata)
  477. {
  478. free (spdata->spans);
  479. free (spdata);
  480. }
  481. }
  482. /* free the record array itself */
  483. free (chead);
  484. /* free pointer */
  485. free (ellipseCache);
  486. }
  487. /* Draw a single arc segment to an miAccumSpans struct, via drawArc() or
  488. * drawZeroArc(). Right and left faces may be specified, for mirroring
  489. * purposes (they're usually computed by miComputeArcs()). The
  490. * accumulation of spans in the miAccumSpans struct will need to be painted
  491. * by a later invocation of fillSpans(). This function updates the ellipse
  492. * span cache. */
  493. static void
  494. miArcSegment (const miGC *pGC, miAccumSpans *accumSpans, miArc tarc, miArcFace *right, miArcFace *left, miEllipseCache *ellipseCache)
  495. {
  496. unsigned int l = pGC->lineWidth;
  497. int a0, a1, startAngle, endAngle;
  498. miArcFace *temp;
  499. if (l == 0) /* map zero width to unit width */
  500. l = 1;
  501. if (tarc.width == 0 || tarc.height == 0)
  502. {
  503. /* degenerate case, either horizontal or vertical arc */
  504. drawZeroArc (accumSpans, &tarc, l, left, right);
  505. return;
  506. }
  507. a0 = tarc.angle1;
  508. a1 = tarc.angle2;
  509. if (a1 > FULLCIRCLE)
  510. a1 = FULLCIRCLE;
  511. else if (a1 < -FULLCIRCLE)
  512. a1 = -FULLCIRCLE;
  513. if (a1 < 0)
  514. {
  515. startAngle = a0 + a1;
  516. endAngle = a0;
  517. temp = right;
  518. right = left;
  519. left = temp;
  520. }
  521. else
  522. {
  523. startAngle = a0;
  524. endAngle = a0 + a1;
  525. }
  526. /*
  527. * bounds check the two angles
  528. */
  529. if (startAngle < 0)
  530. startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
  531. if (startAngle >= FULLCIRCLE)
  532. startAngle = startAngle % FULLCIRCLE;
  533. if (endAngle < 0)
  534. endAngle = FULLCIRCLE - (-endAngle) % FULLCIRCLE;
  535. if (endAngle > FULLCIRCLE)
  536. endAngle = (endAngle-1) % FULLCIRCLE + 1;
  537. if ((startAngle == endAngle) && a1)
  538. {
  539. startAngle = 0;
  540. endAngle = FULLCIRCLE;
  541. }
  542. /* Draw the arc to memory, as a set of spans (accumulated spans must
  543. later be painted and deallocated by invoking fillSpans()). This
  544. updates the ellipse span cache. */
  545. drawArc (accumSpans,
  546. &tarc, l, startAngle, endAngle, right, left,
  547. ellipseCache);
  548. }
  549. /* Paint a wide, complete [i.e. undashed] ellipse, immediately. I.e.,
  550. paint it to a miPaintedSet, not to an in-core miAccumSpans struct.
  551. Called by miPolyArc if angle is at least 360 degrees. Calls
  552. miComputeWideEllipse(), and updates the ellipse span cache. */
  553. static void
  554. miFillWideEllipse (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArc *parc, miEllipseCache *ellipseCache)
  555. {
  556. miArcSpanData *spdata;
  557. bool mustFree;
  558. miArcSpan *arcSpan, *finalArcSpan;
  559. int xorg, yorgu, yorgl;
  560. int numArcSpans, n;
  561. int numSpans_downward, numSpans_upward, numSpans, botSpans;
  562. miPoint *pptInit, *ppt_downward, *ppt_upward;
  563. unsigned int *pwidthInit, *pwidth_downward, *pwidth_upward;
  564. /* Compute span data for whole wide ellipse, updating the ellipse cache.
  565. Return value will be a pointer to a miArcSpanData struct, which is
  566. basically an array of miArcSpan's indexed by y. A miArcSpan comprises
  567. one or two spans. */
  568. spdata = miComputeWideEllipse (pGC->lineWidth, parc, &mustFree, ellipseCache);
  569. if (!spdata)
  570. /* unknown failure, so punt */
  571. return;
  572. arcSpan = spdata->spans; /* first ArcSpan in array */
  573. /* initialize upper and lower y values for span generation;
  574. note spdata->k = height/2 + (linewidth-1)/2, always */
  575. xorg = parc->x + (int)(parc->width >> 1);
  576. yorgu = parc->y + (int)(parc->height >> 1);
  577. yorgl = yorgu + (parc->height & 1);
  578. yorgu -= spdata->k;
  579. yorgl += spdata->k;
  580. /* Add spans both from top of the ellipse (growing downward from y=yorgu)
  581. and from bottom (growing upward from y=yorgl), computed from the
  582. (top ? 1 : 0) + count1 + count2 + (bottom ? 1 : 0)
  583. ArcSpans contained in spdata->spans.
  584. Number of `downward' spans = (top ? 1 : 0) + count1 + 2*count2
  585. + (bot ? [1or2] : 0)
  586. Number of `upward' spans = count1 + (hole ? 1 : 0) + 2*count2
  587. Here [1or2] = (finalArcSpan->rw <= 0 ? 1 : 2), where `finalArcSpan' is
  588. the final ArcSpan in the array spdata->spans. These final 1 or 2
  589. spans, if present, are on the horizontal centerline of the ellipse.
  590. N.B. Presumably
  591. (top ? 1 : 0) + count1 + count2 + (bottom ? 1 : 0) <= k+2,
  592. since the ArcSpans array spdata->spans can contain at most k+2 ArcSpans,
  593. as allocated (see miComputeWideEllipse()). */
  594. numArcSpans = ((spdata->top ? 1 : 0) + spdata->count1
  595. + spdata->count2 + (spdata->bot ? 1 : 0));
  596. finalArcSpan = &(spdata->spans[numArcSpans - 1]);
  597. botSpans = (finalArcSpan->rw <= 0 ? 1 : 2);
  598. numSpans_downward = ((spdata->top ? 1 : 0)
  599. + spdata->count1 + 2 * spdata->count2
  600. + (spdata->bot ? botSpans : 0));
  601. numSpans_upward = (spdata->count1 + (spdata->hole ? 1 : 0)
  602. + 2 * spdata->count2);
  603. numSpans = numSpans_downward + numSpans_upward;
  604. /* allocate span array; will fill it from both ends, so that it will be
  605. sorted (i.e. in y-increasing order) */
  606. pptInit = (miPoint *)mi_xmalloc (numSpans * sizeof(miPoint));
  607. pwidthInit = (unsigned int *)mi_xmalloc (numSpans * sizeof(unsigned int));
  608. ppt_downward = pptInit;
  609. pwidth_downward = pwidthInit;
  610. ppt_upward = pptInit + (numSpans - 1);
  611. pwidth_upward = pwidthInit + (numSpans - 1);
  612. if (spdata->top) /* true if width is even and lw is even */
  613. /* begin with a special `top point' at y=yorgu-1, rather than at
  614. y=yorgu; skip first ArcSpan (it may be bogus) */
  615. {
  616. ppt_downward->x = xorg;
  617. ppt_downward->y = yorgu - 1;
  618. ppt_downward++;
  619. *pwidth_downward++ = 1;
  620. arcSpan++;
  621. }
  622. for (n = spdata->count1; --n >= 0; )
  623. /* Add successive pairs of spans, one upper [beginning at y=yorgu], one
  624. lower [beginning at y=yorgl]. Each pair is taken from one of the
  625. next count1 ArcSpans in spdata; these ArcSpans are singly occupied. */
  626. {
  627. ppt_downward->x = xorg + arcSpan->lx;
  628. ppt_downward->y = yorgu;
  629. *pwidth_downward = arcSpan->lw;
  630. ppt_downward++;
  631. pwidth_downward++;
  632. ppt_upward->x = xorg + arcSpan->lx;
  633. ppt_upward->y = yorgl;
  634. *pwidth_upward = arcSpan->lw;
  635. ppt_upward--;
  636. pwidth_upward--;
  637. yorgu++;
  638. yorgl--;
  639. arcSpan++;
  640. }
  641. if (spdata->hole)
  642. /* Kludge: add a single additional lower point, at x=xorg, y=yorgl (now
  643. decremented), i.e. on the vertical center line. Do not decrement
  644. yorgl further, i.e. do not move upward. (So this extra point will
  645. fit between the two spans of the next `upward' ArcSpan to be drawn.) */
  646. {
  647. ppt_upward->x = xorg;
  648. ppt_upward->y = yorgl;
  649. *pwidth_upward = 1;
  650. ppt_upward--;
  651. pwidth_upward--;
  652. }
  653. for (n = spdata->count2; --n >= 0; )
  654. /* add four spans, two above, two below (each quad taken from one of
  655. the next count2 ArcSpans in spdata; these ArcSpans are doubly
  656. occupied, containing both a left and a right span) */
  657. {
  658. /* left downward span */
  659. ppt_downward->x = xorg + arcSpan->lx;
  660. ppt_downward->y = yorgu;
  661. *pwidth_downward = arcSpan->lw;
  662. ppt_downward++;
  663. pwidth_downward++;
  664. /* right downward span */
  665. ppt_downward->x = xorg + arcSpan->rx;
  666. ppt_downward->y = yorgu;
  667. *pwidth_downward = arcSpan->rw;
  668. ppt_downward++;
  669. pwidth_downward++;
  670. /* left upward span */
  671. ppt_upward->x = xorg + arcSpan->lx;
  672. ppt_upward->y = yorgl;
  673. *pwidth_upward = arcSpan->lw;
  674. ppt_upward--;
  675. pwidth_upward--;
  676. /* right upward span */
  677. ppt_upward->x = xorg + arcSpan->rx;
  678. ppt_upward->y = yorgl;
  679. *pwidth_upward = arcSpan->rw;
  680. ppt_upward--;
  681. pwidth_upward--;
  682. yorgu++;
  683. yorgl--;
  684. arcSpan++;
  685. }
  686. if (spdata->bot) /* true if height is even */
  687. /* To complete the ellipse, add 1 or 2 additional `upper' spans, at
  688. y=yorgu (incremented, i.e. it is now at the horizontal center line,
  689. which is at y = yorg_arc + height_arc/2). The number of spans will
  690. be 2 rather than 1, unless the ellipse is not hollow. */
  691. {
  692. ppt_downward->x = xorg + arcSpan->lx;
  693. ppt_downward->y = yorgu;
  694. *pwidth_downward = arcSpan->lw;
  695. ppt_downward++;
  696. pwidth_downward++;
  697. if (arcSpan->rw > 0)
  698. /* have a second span too */
  699. {
  700. ppt_downward->x = xorg + arcSpan->rx;
  701. ppt_downward->y = yorgu;
  702. *pwidth_downward = arcSpan->rw;
  703. ppt_downward++;
  704. pwidth_downward++;
  705. }
  706. }
  707. if (mustFree) /* free the ArcSpans */
  708. {
  709. free (spdata->spans);
  710. free (spdata);
  711. }
  712. MI_PAINT_SPANS(paintedSet, pixel, numSpans, pptInit, pwidthInit)
  713. }
  714. /* Compute the spans that make up a wide complete ellipse, this way: (1)
  715. search the cache of rasterized ellipses; if no success, (2) scan-convert
  716. the ellipse, and place the spans in the cache for later retrieval, in
  717. case another ellipse of the same size and width needs to be drawn.
  718. Return value will be a pointer to a miArcSpanData struct, which is
  719. basically an array of miArcSpan's indexed by y. A miArcSpan comprises
  720. lx, lwidth, rx, rwidth, i.e., a pair of spans at a given y. `mustFree'
  721. will be set to true if the miArcSpanData struct is a one-shot creation,
  722. not stored in the cache. (This is the case if the ellipse is too large
  723. to be stored in the cache -- a policy issue.)
  724. Called by the low-level draw-to-memory function drawArc(), and also by
  725. miFillWideEllipse(), which paints an entire wide ellipse. This function
  726. calls either miComputeEllipseSpans() or miComputeCircleSpans() to do the
  727. actual computation of spans, i.e. to do scan conversion. */
  728. static miArcSpanData *
  729. miComputeWideEllipse (unsigned int lw, const miArc *parc, bool *mustFree, miEllipseCache *ellipseCache)
  730. {
  731. miArcSpanData *spdata;
  732. cachedEllipse *cent, *lruent;
  733. int k, cache_size;
  734. cachedEllipse fakeent;
  735. /* map zero line width to width unity */
  736. if (lw == 0)
  737. lw = 1;
  738. /* first, attempt to retrieve span data from cache */
  739. if (parc->height <= MAX_CACHEABLE_ELLIPSE_HEIGHT)
  740. {
  741. *mustFree = false;
  742. cent = ellipseCache->lastCacheHit;
  743. if (cent->lw == lw
  744. && cent->width == parc->width && cent->height == parc->height)
  745. /* last hit is still valid; won't need to search */
  746. {
  747. /* hit again; do timestamp, bumping time */
  748. cent->lrustamp = ++(ellipseCache->lrustamp);
  749. return cent->spdata;
  750. }
  751. /* search cache (an array), beginning at 0'th element */
  752. lruent = ellipseCache->ellipses;
  753. cache_size = ellipseCache->size;
  754. for (k = cache_size, cent = lruent; --k >= 0; cent++)
  755. {
  756. /* key on width, height, linewidth */
  757. if (cent->lw == lw
  758. && cent->width == parc->width && cent->height == parc->height)
  759. /* already in cache: a hit */
  760. {
  761. /* do timestamp, bumping time */
  762. cent->lrustamp = ++(ellipseCache->lrustamp);
  763. ellipseCache->lastCacheHit = cent;
  764. return cent->spdata;
  765. }
  766. /* keep track of least recently used record */
  767. if (cent->lrustamp < lruent->lrustamp)
  768. lruent = cent;
  769. }
  770. }
  771. else /* height is huge, ellipse wouldn't be stored in cache */
  772. {
  773. lruent = &fakeent; /* _very_ fake; automatic variable */
  774. lruent->spdata = (miArcSpanData *)NULL;
  775. *mustFree = true;
  776. }
  777. /* data not found in cache, so boot least-recently used record out of
  778. cache, make new one; unless ellipse is too large, that is */
  779. spdata = lruent->spdata;
  780. /* will allocate space for k+2 spans */
  781. k = (int)(parc->height >> 1) + (int)((lw - 1) >> 1);
  782. if (spdata == (miArcSpanData *)NULL || spdata->k != k)
  783. {
  784. if (spdata)
  785. {
  786. free (spdata->spans);
  787. free (spdata);
  788. }
  789. spdata = (miArcSpanData *)mi_xmalloc (sizeof(miArcSpanData));
  790. spdata->spans = (miArcSpan *)mi_xmalloc ((k + 2) * sizeof (miArcSpan));
  791. spdata->k = k; /* k+2 is size of empty span array */
  792. lruent->spdata = spdata;
  793. }
  794. lruent->lrustamp = ++(ellipseCache->lrustamp); /* set timestamp, bump clock */
  795. lruent->lw = lw;
  796. lruent->width = parc->width;
  797. lruent->height = parc->height;
  798. if (lruent != &fakeent) /* non-huge ellipse; store in cache */
  799. ellipseCache->lastCacheHit = lruent;
  800. /* compute spans, place them in the new cache record */
  801. if (parc->width == parc->height)
  802. miComputeCircleSpans (lw, parc, spdata);
  803. else
  804. miComputeEllipseSpans (lw, parc, spdata);
  805. return spdata;
  806. }
  807. /* Compute the spans that make up a complete wide circle, via a fast
  808. integer algorithm. On entry, lw>=1, and `spdata' is a pointer to an
  809. miArcSpanData struct, which is a slot in a record in the ellipse span
  810. cache. It includes spdata->spans, an array of k+2 ArcSpans, which will
  811. be filled in. Here k=height/2 + (lw-1)/2. */
  812. static void
  813. miComputeCircleSpans (unsigned int lw, const miArc *parc, miArcSpanData *spdata)
  814. {
  815. miArcSpan *span;
  816. int doinner;
  817. int x, y, e;
  818. int xk, yk, xm, ym, dx, dy;
  819. int slw, inslw;
  820. int inx = 0, iny, ine = 0;
  821. int inxk = 0, inyk = 0, inxm = 0, inym = 0;
  822. /* compute flags */
  823. /* top=true iff ellipse width is even and line width is even */
  824. spdata->top = !(lw & 1) && !(parc->width & 1) ? true : false;
  825. /* bot=true iff ellipse height is even, so there will be an _odd_
  826. number of spans, from top to bottom */
  827. spdata->bot = !(parc->height & 1) ? true : false;
  828. doinner = -(int)lw;
  829. slw = (int)parc->width - doinner;
  830. y = (int)(parc->height >> 1);
  831. dy = parc->height & 1; /* dy=1 if height is odd */
  832. dx = 1 - dy; /* dx=1 if height is even */
  833. MIWIDEARCSETUP(x, y, dy, slw, e, xk, xm, yk, ym);
  834. inslw = (int)parc->width + doinner;
  835. if (inslw > 0)
  836. {
  837. /* if top=true, will need to add an extra pixel (not included in the
  838. generated list of ArcSpans) in the `hole'; this is a kludge */
  839. spdata->hole = spdata->top;
  840. MIWIDEARCSETUP(inx, iny, dy, inslw, ine, inxk, inxm, inyk, inym);
  841. }
  842. else
  843. {
  844. spdata->hole = false;
  845. doinner = -y;
  846. }
  847. /* Generate the ArcSpans at successive values of y, beginning at the top
  848. of the circle and extending down to its horizontal bisector. Also,
  849. fill in the count1/count2/top/bottom elements of the miArcSpanData
  850. struct pointed to by spdata. There will be
  851. (top ? 1 : 0) + count1 + count2 + (bottom ? 1 : 0)
  852. ArcSpans in all. The first ones [(top ? 1 : 0) + count1 in number]
  853. will be single-occupied, i.e., they will include only one span.
  854. The latter ones [count2 + (bottom ? 1 : 0) in number]
  855. will be doubly-occupied, i.e., they will include two spans.
  856. For the special role of the very first and very last ArcSpans in the
  857. list, to fix which the `top' and `bottom' kludge flags were
  858. introduced, see following comments. */
  859. /* If top=true, first ArcSpan generated by the following `while' loop
  860. will be bogus, and will need to be replaced, when drawing, by a single
  861. point. So decrement count1 to compensate. */
  862. spdata->count1 = -doinner - (spdata->top ? 1 : 0);
  863. spdata->count2 = y + doinner;
  864. span = spdata->spans;
  865. /* initial value of y is (width+lw)/2 + (1 if height is even) */
  866. while (y)
  867. {
  868. MIFILLARCSTEP(x, y, e, xk, xm, yk, ym, dx, slw); /* y-- */
  869. span->lx = dy - x;
  870. if (++doinner <= 0)
  871. {
  872. span->lw = slw;
  873. span->rx = 0;
  874. span->rw = span->lx + slw;
  875. }
  876. else
  877. {
  878. MIFILLINARCSTEP(inx, iny, ine, inxk, inxm, inyk, inym, dx, inslw);
  879. span->lw = x - inx;
  880. span->rx = dy - inx + inslw;
  881. span->rw = inx - x + slw - inslw;
  882. }
  883. span++;
  884. }
  885. if (spdata->bot)
  886. /* last-generated ArcSpan, on the horizontal center line, is special,
  887. so modify it and decrement count2 (or count1) to compensate */
  888. {
  889. if (spdata->count2 > 0)
  890. spdata->count2--;
  891. else
  892. /* no two-span ArcSpans at all; ellipse isn't hollow */
  893. {
  894. if (lw > parc->height)
  895. span[-1].rx = span[-1].rw = -(((int)lw - (int)parc->height) >> 1);
  896. else
  897. span[-1].rw = 0;
  898. spdata->count1--;
  899. }
  900. }
  901. }
  902. /*
  903. The following mathematics is the background for the algorithm used in
  904. miComputeEllipseSpans() below, which scan-converts a wide ellipse.
  905. The following three equations combine to describe the boundaries of a wide
  906. ellipse, if it is drawn with a circular brush.
  907. x^2/w^2 + y^2/h^2 = 1 ellipse itself
  908. (X-x)^2 + (Y-y)^2 = r^2 circle at (x, y) on the ellipse
  909. (Y-y) = (X-x)*w^2*y/(h^2*x) normal at (x, y) on the ellipse
  910. These lead to a quartic relating Y and y
  911. y^4 - (2Y)y^3 + (Y^2 + (h^4 - w^2*r^2)/(w^2 - h^2))y^2
  912. - (2Y*h^4/(w^2 - h^2))y + (Y^2*h^4)/(w^2 - h^2) = 0
  913. The reducible cubic obtained from this quartic is
  914. z^3 - (3N)z^2 - 2V = 0
  915. where
  916. N = (Y^2 + (h^4 - w^2*r^2/(w^2 - h^2)))/6
  917. V = w^2*r^2*Y^2*h^4/(4 *(w^2 - h^2)^2)
  918. Let
  919. t = z - N
  920. p = -N^2
  921. q = -N^3 - V
  922. Then we get
  923. t^3 + 3pt + 2q = 0
  924. The discriminant of this cubic is
  925. D = q^2 + p^3
  926. When D > 0, a real root is obtained as
  927. z = N + cbrt(-q+sqrt(D)) + cbrt(-q-sqrt(D))
  928. When D < 0, a real root is obtained as
  929. z = N - 2m*cos(acos(-q/m^3)/3)
  930. where
  931. m = sqrt(|p|) * sign(q)
  932. Given a real root Z of the cubic, the roots of the quartic are the roots
  933. of the two quadratics
  934. y^2 + ((b+A)/2)y + (Z + (bZ - d)/A) = 0
  935. where
  936. A = +/- sqrt(8Z + b^2 - 4c)
  937. b, c, d are the cubic, quadratic, and linear coefficients of the quartic
  938. Some experimentation is then required to determine which solutions
  939. correspond to the inner and outer boundaries of the wide ellipse. */
  940. /* Compute the spans that make up a complete wide ellipse, via a floating
  941. point algorithm motivated by the above math. On entry, lw>=1, and
  942. `spdata' is a pointer to an miArcSpanData struct, which is a slot in a
  943. record in the ellipse span cache. It includes spdata->spans, an array
  944. of k+2 ArcSpans, which will be filled in. Here
  945. k=height/2 + (lw-1)/2. */
  946. static void
  947. miComputeEllipseSpans (unsigned int lw, const miArc *parc, miArcSpanData *spdata)
  948. {
  949. miArcSpan *span;
  950. double w, h, r, xorg;
  951. double Hs, Hf, WH, K, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
  952. double A, T, b, d, x, y, t, inx, outx = 0, hepp, hepm;
  953. int flip;
  954. bool solution;
  955. /* compute flags */
  956. /* top=true iff ellipse width is even and line width is even */
  957. spdata->top = !(lw & 1) && !(parc->width & 1) ? true : false;
  958. /* bot=true iff ellipse height is even, so there will be an _odd_
  959. number of spans, from top to bottom */
  960. spdata->bot = !(parc->height & 1) ? true : false;
  961. /* a kludge */
  962. spdata->hole = ((spdata->top
  963. && parc->height * lw <= parc->width * parc->width
  964. && lw < parc->height) ? true : false);
  965. w = 0.5 * parc->width;
  966. h = 0.5 * parc->height;
  967. r = 0.5 * lw;
  968. rs = r * r;
  969. Hs = h * h;
  970. WH = w * w - Hs;
  971. Nk = w * r;
  972. Vk = (Nk * Hs) / (WH + WH);
  973. Hf = Hs * Hs;
  974. Nk = (Hf - Nk * Nk) / WH;
  975. Fk = Hf / WH;
  976. hepp = h + EPSILON;
  977. hepm = h - EPSILON;
  978. K = h + ((lw - 1) >> 1);
  979. if (parc->width & 1)
  980. xorg = .5;
  981. else
  982. xorg = 0.0;
  983. spdata->count1 = 0;
  984. spdata->count2 = 0;
  985. /* Generate list of spans, going downward from top of ellipse,
  986. i.e. more or less at y = yorgu = yorg_arc + height_arc/2 - k.
  987. Most of these will be mirrored, going upward from the bottom
  988. of the ellipse, starting at y = yorgu = yorg_arc + height_arc/2 + k. */
  989. span = spdata->spans;
  990. if (spdata->top)
  991. /* top=true if ellipse width is even and line width is even; if so,
  992. begin with a special (non-mirrored) ArcSpan containing a single `top
  993. point', at y=yorgu-1 */
  994. {
  995. span->lx = 0;
  996. span->lw = 1;
  997. span++;
  998. }
  999. /* generate count1 + count2 ArcSpans, at y=yorgu, y=yorgu+1,...;
  1000. count1 one-span ArcSpans come first, then count2 two-span ArcSpans */
  1001. for (; K > 0.0; K -= 1.0)
  1002. {
  1003. N = (K * K + Nk) / 6.0;
  1004. Nc = N * N * N;
  1005. Vr = Vk * K;
  1006. t = Nc + Vr * Vr;
  1007. d = Nc + t;
  1008. if (d < 0.0)
  1009. {
  1010. d = Nc;
  1011. b = N;
  1012. if ( (b < 0.0) == (t < 0.0) )
  1013. {
  1014. b = -b;
  1015. d = -d;
  1016. }
  1017. Z = N - 2.0 * b * cos(acos(-t / d) / 3.0);
  1018. if ( (Z < 0.0) == (Vr < 0.0) )
  1019. flip = 2;
  1020. else
  1021. flip = 1;
  1022. }
  1023. else
  1024. {
  1025. d = Vr * sqrt(d);
  1026. Z = N + cbrt(t + d) + cbrt(t - d);
  1027. flip = 0;
  1028. }
  1029. A = sqrt((Z + Z) - Nk);
  1030. T = (Fk - Z) * K / A;
  1031. inx = 0.0;
  1032. solution = false;
  1033. b = -A + K;
  1034. d = b * b - 4 * (Z + T);
  1035. if (d >= 0)
  1036. {
  1037. d = sqrt(d);
  1038. y = 0.5 * (b + d);
  1039. if ((y >= 0.0) && (y < hepp))
  1040. {
  1041. solution = true;
  1042. if (y > hepm)
  1043. y = h;
  1044. t = y / h;
  1045. x = w * sqrt(1 - (t * t));
  1046. t = K - y;
  1047. t = sqrt(rs - (t * t));
  1048. if (flip == 2)
  1049. inx = x - t;
  1050. else
  1051. outx = x + t;
  1052. }
  1053. }
  1054. b = A + K;
  1055. d = b * b - 4 * (Z - T);
  1056. /* Because of the large magnitudes involved, we lose enough precision
  1057. * that sometimes we end up with a negative value near the axis, when
  1058. * it should be positive. This is a workaround.
  1059. */
  1060. if (d < 0 && !solution)
  1061. d = 0.0;
  1062. if (d >= 0)
  1063. {
  1064. d = sqrt(d);
  1065. y = 0.5 * (b + d);
  1066. if (y < hepp)
  1067. {
  1068. if (y > hepm)
  1069. y = h;
  1070. t = y / h;
  1071. x = w * sqrt(1 - (t * t));
  1072. t = K - y;
  1073. inx = x - sqrt(rs - (t * t));
  1074. }
  1075. y = 0.5 * (b - d);
  1076. if (y >= 0.0)
  1077. {
  1078. if (y > hepm)
  1079. y = h;
  1080. t = y / h;
  1081. x = w * sqrt(1 - (t * t));
  1082. t = K - y;
  1083. t = sqrt(rs - (t * t));
  1084. if (flip == 1)
  1085. inx = x - t;
  1086. else
  1087. outx = x + t;
  1088. }
  1089. }
  1090. span->lx = ICEIL(xorg - outx);
  1091. if (inx <= 0.0)
  1092. {
  1093. /* a one-span ArcSpan (they come first) */
  1094. spdata->count1++;
  1095. span->lw = ICEIL(xorg + outx) - span->lx;
  1096. span->rx = ICEIL(xorg + inx);
  1097. span->rw = -ICEIL(xorg - inx);
  1098. }
  1099. else
  1100. {
  1101. /* a two-span ArcSpan (they come second) */
  1102. spdata->count2++;
  1103. span->lw = ICEIL(xorg - inx) - span->lx;
  1104. span->rx = ICEIL(xorg + inx);
  1105. span->rw = ICEIL(xorg + outx) - span->rx;
  1106. }
  1107. span++;
  1108. }
  1109. if (spdata->bot)
  1110. /* bot=true if ellipse height is even; if so, complete the ellipse by
  1111. adding a final ArcSpan at the horizontal center line, containing
  1112. either two spans or one span (if the ellipse isn't hollow) */
  1113. {
  1114. outx = w + r;
  1115. if (r >= h && r <= w)
  1116. inx = 0.0;
  1117. else if (Nk < 0.0 && -Nk < Hs)
  1118. {
  1119. inx = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
  1120. if (inx > w - r)
  1121. inx = w - r;
  1122. }
  1123. else
  1124. inx = w - r;
  1125. span->lx = ICEIL(xorg - outx);
  1126. if (inx <= 0.0)
  1127. {
  1128. span->lw = ICEIL(xorg + outx) - span->lx;
  1129. span->rx = ICEIL(xorg + inx);
  1130. span->rw = -ICEIL(xorg - inx);
  1131. }
  1132. else
  1133. {
  1134. span->lw = ICEIL(xorg - inx) - span->lx;
  1135. span->rx = ICEIL(xorg + inx);
  1136. span->rw = ICEIL(xorg + outx) - span->rx;
  1137. }
  1138. }
  1139. if (spdata->hole)
  1140. /* convert the final one-span ArcSpan to the initial two-span ArcSpan,
  1141. so that there will be a one-pixel `hole' to be filled */
  1142. {
  1143. span = &spdata->spans[spdata->count1];
  1144. span->lw = -span->lx;
  1145. span->rx = 1;
  1146. span->rw = span->lw;
  1147. spdata->count1--;
  1148. spdata->count2++;
  1149. }
  1150. }
  1151. /**********************************************************************/
  1152. /* miComputeArcs() and miFreeArcs(), called by miPolyArc(). */
  1153. /**********************************************************************/
  1154. /* Compute arc segments, caps, and joins in a polyarc, taking account of
  1155. dashing. Return value is a list of miPolyArcs structs, indexed by pixel
  1156. paint type, which will need to be freed with miFreeArcs(). If dashing,
  1157. sub-pixel placement of arc segment endpoints will normally occur. */
  1158. static miPolyArcs *
  1159. miComputeArcs (const miGC *pGC, const miArc *parcs, int narcs)
  1160. {
  1161. bool isDashed, isDoubleDash;
  1162. miPolyArcs *arcs;
  1163. int i, start, k, nextk;
  1164. miArcData *data;
  1165. int numPixels;
  1166. int paintType, paintTypeStart, prevPaintType;
  1167. int dashNum, dashIndex, dashRemaining;
  1168. int dashNumStart, dashIndexStart, dashRemainingStart;
  1169. isDashed = (pGC->lineStyle == (int)MI_LINE_SOLID ? false : true);
  1170. isDoubleDash = (pGC->lineStyle == (int)MI_LINE_DOUBLE_DASH ? true : false);
  1171. numPixels = pGC->numPixels;
  1172. /* allocate and initialize list of miPolyArcs that will be returned */
  1173. arcs = (miPolyArcs *) mi_xmalloc (numPixels * sizeof(miPolyArcs));
  1174. for (paintType = 0; paintType < numPixels; paintType++)
  1175. {
  1176. arcs[paintType].arcs = (miArcData *)NULL;
  1177. arcs[paintType].narcs = 0;
  1178. arcs[paintType].arcSize = 0; /* slots allocated */
  1179. arcs[paintType].caps = (miArcCapStruct *)NULL;
  1180. arcs[paintType].ncaps = 0;
  1181. arcs[paintType].capSize = 0; /* slots allocated */
  1182. arcs[paintType].joins = (miArcJoinStruct *)NULL;
  1183. arcs[paintType].njoins = 0;
  1184. arcs[paintType].joinSize = 0; /* slots allocated */
  1185. }
  1186. /* allocate and fill temporary struct with starting point, ending point,
  1187. self-join status of each elliptic arc */
  1188. #define todeg(xAngle) (((double) (xAngle)) / 64.0)
  1189. data = (miArcData *) mi_xmalloc (narcs * sizeof (miArcData));
  1190. for (i = 0; i < narcs; i++)
  1191. {
  1192. double a0, a1;
  1193. int angle2;
  1194. a0 = todeg (parcs[i].angle1);
  1195. angle2 = parcs[i].angle2;
  1196. if (angle2 > FULLCIRCLE)
  1197. angle2 = FULLCIRCLE;
  1198. else if (angle2 < -FULLCIRCLE)
  1199. angle2 = -FULLCIRCLE;
  1200. data[i].selfJoin = ((angle2 == FULLCIRCLE) || (angle2 == -FULLCIRCLE)
  1201. ? true : false);
  1202. a1 = todeg (parcs[i].angle1 + angle2);
  1203. data[i].x0 = parcs[i].x + (double) parcs[i].width / 2*(1 + miDcos (a0));
  1204. data[i].y0 = parcs[i].y + (double) parcs[i].height / 2*(1 - miDsin (a0));
  1205. data[i].x1 = parcs[i].x + (double) parcs[i].width / 2*(1 + miDcos (a1));
  1206. data[i].y1 = parcs[i].y + (double) parcs[i].height / 2*(1 - miDsin (a1));
  1207. }
  1208. /* initialize paint type and dashing state (latter is not used in `solid'
  1209. case) */
  1210. paintType = 1;
  1211. dashNum = 0;
  1212. dashIndex = 0;
  1213. dashRemaining = 0;
  1214. if (isDashed)
  1215. /* take offsetting into account */
  1216. {
  1217. int dashOffset = 0;
  1218. /* alter paint type (for first dash) and dashing state */
  1219. miStepDash (pGC->dashOffset, &dashNum, &dashIndex,
  1220. pGC->dash, pGC->numInDashList, &dashOffset);
  1221. paintType = (dashNum & 1) ? 0 : 1 + ((dashNum / 2) % (numPixels - 1));
  1222. dashRemaining = (int)(pGC->dash[dashIndex]) - dashOffset;
  1223. }
  1224. /* save paint type and dashing state (will reset at each unjoined arc) */
  1225. paintTypeStart = paintType;
  1226. dashNumStart = dashNum;
  1227. dashIndexStart = dashIndex;
  1228. dashRemainingStart = dashRemaining;
  1229. /* iterate backward over arcs; determine whether cap will be required
  1230. after each arc, and stop when first such is seen */
  1231. for (i = narcs - 1; i >= 0; i--)
  1232. {
  1233. int j;
  1234. j = i + 1;
  1235. if (j == narcs)
  1236. j = 0;
  1237. if (data[i].selfJoin || i == j ||
  1238. (UNEQUAL (data[i].x1, data[j].x0) ||
  1239. UNEQUAL (data[i].y1, data[j].y0)))
  1240. {
  1241. /* if starting in `on' phase, add a cap at right end */
  1242. if (paintType != 0 || isDoubleDash)
  1243. addCap (&arcs[paintType], RIGHT_END, 0);
  1244. break;
  1245. }
  1246. }
  1247. /* iterate forward over all successive pairs of arcs (wrap if necessary) */
  1248. start = i + 1;
  1249. if (start == narcs)
  1250. start = 0;
  1251. i = start;
  1252. k = nextk = 0;
  1253. /* keep compiler happy by initting prevPaintType too; actually
  1254. unnecessary because first thing drawn won't be a join */
  1255. prevPaintType = paintType;
  1256. for (;;)
  1257. {
  1258. int j, nexti;
  1259. miArcData *arc;
  1260. bool arcsJoin;
  1261. j = i + 1;
  1262. if (j == narcs)
  1263. j = 0;
  1264. nexti = i + 1;
  1265. if (nexti == narcs)
  1266. nexti = 0;
  1267. if (isDashed)
  1268. {
  1269. int startAngle, spanAngle, endAngle;
  1270. int dashAngle, prevDashAngle;
  1271. bool backwards, selfJoin;
  1272. dashMap map;
  1273. miArc xarc;
  1274. /*
  1275. * precompute an approximation map for use in dashing
  1276. */
  1277. computeDashMap (&parcs[i], &map);
  1278. /*
  1279. * compute each individual dash segment using the path
  1280. * length function
  1281. */
  1282. startAngle = parcs[i].angle1;
  1283. spanAngle = parcs[i].angle2;
  1284. if (spanAngle > FULLCIRCLE)
  1285. spanAngle = FULLCIRCLE;
  1286. else if (spanAngle < -FULLCIRCLE)
  1287. spanAngle = -FULLCIRCLE;
  1288. if (startAngle < 0)
  1289. startAngle = FULLCIRCLE - (-startAngle) % FULLCIRCLE;
  1290. if (startAngle >= FULLCIRCLE)
  1291. startAngle = startAngle % FULLCIRCLE;
  1292. endAngle = startAngle + spanAngle;
  1293. backwards = (spanAngle < 0 ? true : false);
  1294. dashAngle = startAngle;
  1295. selfJoin = (data[i].selfJoin && (paintType != 0 || isDoubleDash)
  1296. ? true : false);
  1297. /*
  1298. * add dashed arcs to each bucket
  1299. */
  1300. arc = (miArcData *)NULL;
  1301. while (dashAngle != endAngle)
  1302. {
  1303. prevDashAngle = dashAngle;
  1304. dashAngle = computeAngleFromPath (prevDashAngle, endAngle, &map,
  1305. &dashRemaining, backwards);
  1306. /* avoid troubles with huge arcs and small dashes */
  1307. if (dashAngle == prevDashAngle)
  1308. {
  1309. if (backwards)
  1310. dashAngle--;
  1311. else
  1312. dashAngle++;
  1313. }
  1314. if (paintType != 0 || isDoubleDash)
  1315. {
  1316. xarc = parcs[i];
  1317. spanAngle = prevDashAngle;
  1318. if (spanAngle < 0)
  1319. spanAngle = FULLCIRCLE - (-spanAngle) % FULLCIRCLE;
  1320. if (spanAngle >= FULLCIRCLE)
  1321. spanAngle = spanAngle % FULLCIRCLE;
  1322. xarc.angle1 = spanAngle;
  1323. spanAngle = dashAngle - prevDashAngle;
  1324. if (backwards)
  1325. {
  1326. if (dashAngle > prevDashAngle)
  1327. spanAngle = - FULLCIRCLE + spanAngle;
  1328. }
  1329. else
  1330. {
  1331. if (dashAngle < prevDashAngle)
  1332. spanAngle = FULLCIRCLE + spanAngle;
  1333. }
  1334. if (spanAngle > FULLCIRCLE)
  1335. spanAngle = FULLCIRCLE;
  1336. if (spanAngle < -FULLCIRCLE)
  1337. spanAngle = -FULLCIRCLE;
  1338. xarc.angle2 = spanAngle;
  1339. arc = addArc (&arcs[paintType], &xarc);
  1340. /*
  1341. * cap each end of an on/off dash
  1342. */
  1343. if (!isDoubleDash)
  1344. {
  1345. if (prevDashAngle != startAngle)
  1346. addCap (&arcs[paintType],
  1347. RIGHT_END, arc - arcs[paintType].arcs);
  1348. if (dashAngle != endAngle)
  1349. addCap (&arcs[paintType],
  1350. LEFT_END, arc - arcs[paintType].arcs);
  1351. }
  1352. arc->cap = arcs[paintType].ncaps;
  1353. arc->join = arcs[paintType].njoins;
  1354. arc->render = false;
  1355. arc->selfJoin = false;
  1356. if (dashAngle == endAngle)
  1357. arc->selfJoin = selfJoin;
  1358. }
  1359. prevPaintType = paintType;
  1360. if (dashRemaining <= 0)
  1361. /* on to next dash (negative means overshoot due to
  1362. rounding; positive means undershoot due to rounding, in
  1363. which case we don't bump dashNum or dashIndex, or toggle
  1364. the dash phase: next dash will have same paint type */
  1365. {
  1366. dashNum++;
  1367. dashIndex++;
  1368. if (dashIndex == pGC->numInDashList) /* wrap */
  1369. dashIndex = 0;
  1370. /* recompute paintType, dashRemaining for next dash */
  1371. paintType =
  1372. (dashNum & 1) ? 0 : 1 + ((dashNum / 2) % (numPixels - 1));
  1373. dashRemaining = (int)(pGC->dash[dashIndex]);
  1374. }
  1375. }
  1376. /*
  1377. * make sure a place exists for the position data if
  1378. * we drew (i.e. didn't draw) a zero-length arc
  1379. */
  1380. if (startAngle == endAngle) /* zero-length */
  1381. {
  1382. prevPaintType = paintType;
  1383. if (isDoubleDash == false && paintType == 0)
  1384. /* use color of most recent `on' dash */
  1385. {
  1386. if (dashNum == 0)
  1387. prevPaintType = numPixels - 1;
  1388. else /* can use infix % operator */
  1389. prevPaintType =
  1390. ((dashNum - 1) & 1) ? 0 : 1 + (((dashNum - 1)/ 2) % (numPixels - 1));
  1391. }
  1392. arc = addArc (&arcs[prevPaintType], &parcs[i]);
  1393. arc->join = arcs[prevPaintType].njoins;
  1394. arc->cap = arcs[prevPaintType].ncaps;
  1395. arc->selfJoin = data[i].selfJoin;
  1396. }
  1397. }
  1398. else
  1399. /* not dashing; just add whole (solid) arc */
  1400. {
  1401. arc = addArc (&arcs[paintType], &parcs[i]);
  1402. arc->join = arcs[paintType].njoins;
  1403. arc->cap = arcs[paintType].ncaps;
  1404. arc->selfJoin = data[i].selfJoin;
  1405. prevPaintType = paintType;
  1406. }
  1407. if (prevPaintType != 0 || isDoubleDash)
  1408. k = arcs[prevPaintType].narcs - 1;
  1409. if (paintType != 0 || isDoubleDash)
  1410. nextk = arcs[paintType].narcs;
  1411. if (nexti == start)
  1412. {
  1413. nextk = 0;
  1414. if (isDashed)
  1415. /* re-initialize paint type and dashing state */
  1416. {
  1417. paintType = paintTypeStart;
  1418. dashNum = dashNumStart;
  1419. dashIndex = dashIndexStart;
  1420. dashRemaining = dashRemainingStart;
  1421. }
  1422. }
  1423. /* does the successive pair of arcs join? */
  1424. arcsJoin = (narcs > 1 && i != j
  1425. && ISEQUAL (data[i].x1, data[j].x0)
  1426. && ISEQUAL (data[i].y1, data[j].y0)
  1427. && data[i].selfJoin == false
  1428. && data[j].selfJoin == false) ? true : false;
  1429. if (arc != (miArcData *)NULL)
  1430. {
  1431. if (arcsJoin)
  1432. arc->render = false;
  1433. else
  1434. /* no join; so add directive to render first arc */
  1435. arc->render = true;
  1436. }
  1437. if (arcsJoin
  1438. && (prevPaintType != 0 || isDoubleDash)
  1439. && (paintType != 0 || isDoubleDash))
  1440. /* arcs join, and both are `on' */
  1441. {
  1442. int joinPaintType;
  1443. joinPaintType = paintType;
  1444. if (isDoubleDash)
  1445. {
  1446. if (nexti == start)
  1447. joinPaintType = paintTypeStart;
  1448. /* if join is right at the dash and there are two colors to
  1449. choose from, draw join in a foreground color */
  1450. if (joinPaintType == 0)
  1451. {
  1452. if (prevPaintType != 0)
  1453. joinPaintType = prevPaintType;
  1454. else /* shouldn't happen; just use next dash's color */
  1455. joinPaintType =
  1456. ((dashNum + 1) & 1) ? 0 : 1 + (((dashNum + 1)/ 2) % (numPixels - 1));
  1457. }
  1458. }
  1459. if (joinPaintType != 0 || isDoubleDash)
  1460. {
  1461. addJoin (&arcs[joinPaintType],
  1462. LEFT_END, k, prevPaintType,
  1463. RIGHT_END, nextk, paintType);
  1464. arc->join = arcs[prevPaintType].njoins;
  1465. }
  1466. }
  1467. else
  1468. /* arcs don't join (or if they do, at least one is `off') */
  1469. {
  1470. /*
  1471. * cap the left end of this arc
  1472. * unless it joins itself
  1473. */
  1474. if ((prevPaintType != 0 || isDoubleDash)
  1475. && arc->selfJoin == false)
  1476. {
  1477. addCap (&arcs[prevPaintType], LEFT_END, k);
  1478. arc->cap = arcs[prevPaintType].ncaps;
  1479. }
  1480. if (isDashed && arcsJoin == false)
  1481. /* re-initialize paint type and dashing state */
  1482. {
  1483. paintType = paintTypeStart;
  1484. dashNum = dashNumStart;
  1485. dashIndex = dashIndexStart;
  1486. dashRemaining = dashRemainingStart;
  1487. }
  1488. nextk = arcs[paintType].narcs;
  1489. if (nexti == start)
  1490. {
  1491. nextk = 0;
  1492. /* re-initialize paint type and dashing state */
  1493. paintType = paintTypeStart;
  1494. dashNum = dashNumStart;
  1495. dashIndex = dashIndexStart;
  1496. dashRemaining = dashRemainingStart;
  1497. }
  1498. /*
  1499. * cap the right end of the next arc. If the
  1500. * next arc is actually the first arc, only
  1501. * cap it if it joins with this arc. This
  1502. * case will occur when the final dash segment
  1503. * of an on/off dash is off. Of course, this
  1504. * cap will be drawn at a strange time, but that
  1505. * hardly matters...
  1506. */
  1507. if ((paintType != 0 || isDoubleDash)
  1508. && (nexti != start || (arcsJoin && isDashed)))
  1509. addCap (&arcs[paintType], RIGHT_END, nextk);
  1510. }
  1511. i = nexti;
  1512. if (i == start)
  1513. /* have now iterated over all successive pairs (cyclically) */
  1514. break;
  1515. }
  1516. /* make sure the last arc if any (i.e. miArcData struct) in each
  1517. paint-type-specific miPolyArcs struct includes a `render' directive */
  1518. for (paintType = 0; paintType < numPixels; paintType++)
  1519. if (arcs[paintType].narcs > 0)
  1520. {
  1521. arcs[paintType].arcs[arcs[paintType].narcs-1].render = true;
  1522. arcs[paintType].arcs[arcs[paintType].narcs-1].join =
  1523. arcs[paintType].njoins;
  1524. arcs[paintType].arcs[arcs[paintType].narcs-1].cap =
  1525. arcs[paintType].ncaps;
  1526. }
  1527. free (data);
  1528. /* return the array of paint-type-specific miPolyArcs structs */
  1529. return arcs;
  1530. }
  1531. /* Free a list of arc segments (i.e. dashes) for an incomplete ellipse,
  1532. indexed by pixel paint type, that was computed by miComputeArcs(). */
  1533. static void
  1534. miFreeArcs(const miGC *pGC, miPolyArcs *arcs)
  1535. {
  1536. int paintType;
  1537. for (paintType = 0; paintType < pGC->numPixels; paintType++)
  1538. {
  1539. if (arcs[paintType].narcs > 0)
  1540. free (arcs[paintType].arcs);
  1541. if (arcs[paintType].njoins > 0)
  1542. free (arcs[paintType].joins);
  1543. if (arcs[paintType].ncaps > 0)
  1544. free (arcs[paintType].caps);
  1545. }
  1546. free (arcs);
  1547. }
  1548. /**********************************************************************/
  1549. /* addCap(), addJoin(), addArc(). These three helper functions are used by
  1550. miComputeArcs(). */
  1551. /**********************************************************************/
  1552. #define ADD_REALLOC_STEP 20
  1553. /* helper function called by miComputeArcs(); add a cap to the array of
  1554. miArcCapStructs in a miPolyArcs struct */
  1555. static void
  1556. addCap (miPolyArcs *polyArcs, int end, int arcIndex)
  1557. {
  1558. miArcCapStruct *cap;
  1559. if (polyArcs->ncaps == polyArcs->capSize)
  1560. /* expand array */
  1561. {
  1562. int newsize = polyArcs->capSize + ADD_REALLOC_STEP;
  1563. miArcCapStruct *newcaps;
  1564. newcaps = (miArcCapStruct *) mi_xrealloc (polyArcs->caps,
  1565. newsize * sizeof(miArcCapStruct));
  1566. polyArcs->caps = newcaps;
  1567. polyArcs->capSize = newsize;
  1568. }
  1569. cap = &(polyArcs->caps[polyArcs->ncaps]);
  1570. cap->end = end;
  1571. cap->arcIndex = arcIndex;
  1572. ++(polyArcs->ncaps);
  1573. }
  1574. /* helper function called by miComputeArcs(); add a join to the array of
  1575. miArcJoinStructs in a miPolyArcs struct */
  1576. static void
  1577. addJoin (miPolyArcs *polyArcs, int end0, int index0, int paintType0, int end1, int index1, int paintType1)
  1578. {
  1579. miArcJoinStruct *join;
  1580. if (polyArcs->njoins == polyArcs->joinSize)
  1581. /* expand array */
  1582. {
  1583. int newsize = polyArcs->joinSize + ADD_REALLOC_STEP;
  1584. miArcJoinStruct *newjoins;
  1585. newjoins = (miArcJoinStruct *) mi_xrealloc (polyArcs->joins,
  1586. newsize * sizeof(miArcJoinStruct));
  1587. polyArcs->joins = newjoins;
  1588. polyArcs->joinSize = newsize;
  1589. }
  1590. join = &(polyArcs->joins[polyArcs->njoins]);
  1591. join->end0 = end0;
  1592. join->arcIndex0 = index0;
  1593. join->paintType0 = paintType0;
  1594. join->end1 = end1;
  1595. join->arcIndex1 = index1;
  1596. join->paintType1 = paintType1;
  1597. ++(polyArcs->njoins);
  1598. }
  1599. /* helper function called by miComputeArcs(); add a arc (i.e. an miArc) to
  1600. the array of miArcData structs in a miPolyArcs struct, and return a
  1601. pointer to the new miArcData struct */
  1602. static miArcData *
  1603. addArc (miPolyArcs *polyArcs, const miArc *xarc)
  1604. {
  1605. miArcData *arc;
  1606. if (polyArcs->narcs == polyArcs->arcSize)
  1607. /* expand array */
  1608. {
  1609. int newsize = polyArcs->arcSize + ADD_REALLOC_STEP;
  1610. miArcData *newarcs;
  1611. newarcs = (miArcData *) mi_xrealloc (polyArcs->arcs,
  1612. newsize * sizeof(miArcData));
  1613. polyArcs->arcs = newarcs;
  1614. polyArcs->arcSize = newsize;
  1615. }
  1616. arc = &(polyArcs->arcs[polyArcs->narcs]);
  1617. arc->arc = *xarc;
  1618. ++(polyArcs->narcs);
  1619. return arc;
  1620. }
  1621. /**********************************************************************/
  1622. /* miArcJoin() and miArcCap(). These two low-level functions are called by
  1623. miPolyArc(). They draw joins and caps by calling miFillSppPoly(), which
  1624. calls the low-level paint function. */
  1625. /**********************************************************************/
  1626. /* Draw a join between two contiguous arcs, by calling miFillSppPoly(). */
  1627. static void
  1628. miArcJoin (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArcFace *pLeft, const miArcFace *pRight, int xOrgLeft, int yOrgLeft, double xFtransLeft, double yFtransLeft, int xOrgRight, int yOrgRight, double xFtransRight, double yFtransRight)
  1629. {
  1630. SppPoint center, corner, otherCorner;
  1631. SppPoint poly[5];
  1632. SppPoint *pArcPts;
  1633. int cpt;
  1634. SppArc arc;
  1635. miArcFace Right, Left;
  1636. int polyLen = 0;
  1637. int xOrg, yOrg;
  1638. double xFtrans, yFtrans;
  1639. double a;
  1640. double width;
  1641. double halftheta;
  1642. xOrg = (xOrgRight + xOrgLeft) / 2;
  1643. yOrg = (yOrgRight + yOrgLeft) / 2;
  1644. xFtrans = (xFtransLeft + xFtransRight) / 2;
  1645. yFtrans = (yFtransLeft + yFtransRight) / 2;
  1646. Right = *pRight;
  1647. translateBounds (&Right, xOrg - xOrgRight, yOrg - yOrgRight,
  1648. xFtrans - xFtransRight, yFtrans - yFtransRight);
  1649. Left = *pLeft;
  1650. translateBounds (&Left, xOrg - xOrgLeft, yOrg - yOrgLeft,
  1651. xFtrans - xFtransLeft, yFtrans - yFtransLeft);
  1652. pRight = &Right;
  1653. pLeft = &Left;
  1654. if (pRight->clock.x == pLeft->counterClock.x
  1655. && pRight->clock.y == pLeft->counterClock.y)
  1656. return;
  1657. /* determine corners of cap */
  1658. center = pRight->center;
  1659. if (0 <= (a = angleBetween (center, pRight->clock, pLeft->counterClock))
  1660. && a <= 180.0)
  1661. {
  1662. corner = pRight->clock;
  1663. otherCorner = pLeft->counterClock;
  1664. }
  1665. else /* interchange to make a <= 180, we hope */
  1666. {
  1667. a = angleBetween (center, pLeft->clock, pRight->counterClock);
  1668. corner = pLeft->clock;
  1669. otherCorner = pRight->counterClock;
  1670. }
  1671. width = (pGC->lineWidth ? pGC->lineWidth : 1);
  1672. switch (pGC->joinStyle)
  1673. {
  1674. case MI_JOIN_MITER:
  1675. default:
  1676. /* miter only if MITERLIMIT * sin(theta/2) >= 1.0,
  1677. where theta = 180-a is the join angle */
  1678. if ((halftheta = 0.5 * (180.0 - a)) > 0.0
  1679. && miDsin (halftheta) * pGC->miterLimit >= 1.0)
  1680. /* miter limit not exceeded */
  1681. {
  1682. double ae, ac2, ec2, bc2, de;
  1683. SppPoint e;
  1684. /* miter, i.e. add quadrilateral */
  1685. poly[0] = corner;
  1686. poly[1] = center;
  1687. poly[2] = otherCorner;
  1688. bc2 = ((corner.x - otherCorner.x) * (corner.x - otherCorner.x) +
  1689. (corner.y - otherCorner.y) * (corner.y - otherCorner.y));
  1690. ec2 = 0.25 * bc2;
  1691. ac2 = ((corner.x - center.x) * (corner.x - center.x) +
  1692. (corner.y - center.y) * (corner.y - center.y));
  1693. ae = sqrt (ac2 - ec2);
  1694. de = ec2 / ae;
  1695. e.x = 0.5 * (corner.x + otherCorner.x);
  1696. e.y = 0.5 * (corner.y + otherCorner.y);
  1697. poly[3].x = e.x + de * (e.x - center.x) / ae;
  1698. poly[3].y = e.y + de * (e.y - center.y) / ae;
  1699. poly[4] = corner;
  1700. polyLen = 5;
  1701. }
  1702. else /* miter limit exceeded */
  1703. {
  1704. /* bevel, i.e. add triangle */
  1705. poly[0] = corner;
  1706. poly[1] = center;
  1707. poly[2] = otherCorner;
  1708. poly[3] = corner;
  1709. polyLen = 4;
  1710. }
  1711. miFillSppPoly (paintedSet, pixel,
  1712. polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
  1713. break;
  1714. case MI_JOIN_BEVEL:
  1715. /* add triangle */
  1716. poly[0] = corner;
  1717. poly[1] = center;
  1718. poly[2] = otherCorner;
  1719. poly[3] = corner;
  1720. polyLen = 4;
  1721. miFillSppPoly (paintedSet, pixel,
  1722. polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
  1723. break;
  1724. case MI_JOIN_TRIANGULAR:
  1725. /* add stubby quadrilateral */
  1726. {
  1727. double mid2, mid;
  1728. SppPoint e;
  1729. e.x = 0.5 * (corner.x + otherCorner.x);
  1730. e.y = 0.5 * (corner.y + otherCorner.y);
  1731. mid2 = ((e.x - center.x) * (e.x - center.x) +
  1732. (e.y - center.y) * (e.y - center.y));
  1733. mid = sqrt (mid2);
  1734. poly[0] = corner;
  1735. poly[1] = center;
  1736. poly[2] = otherCorner;
  1737. poly[3].x = e.x + 0.5 * width * (e.x - center.x) / mid;
  1738. poly[3].y = e.y + 0.5 * width * (e.y - center.y) / mid;
  1739. poly[4] = corner;
  1740. polyLen = 5;
  1741. miFillSppPoly (paintedSet, pixel,
  1742. polyLen, poly, xOrg, yOrg, xFtrans, yFtrans);
  1743. }
  1744. break;
  1745. case MI_JOIN_ROUND:
  1746. /* add round cap */
  1747. arc.x = center.x - width/2;
  1748. arc.y = center.y - width/2;
  1749. arc.width = width;
  1750. arc.height = width;
  1751. arc.angle1 = -miDatan2 (corner.y - center.y, corner.x - center.x);
  1752. arc.angle2 = a;
  1753. pArcPts = (SppPoint *) mi_xmalloc (3 * sizeof (SppPoint));
  1754. pArcPts[0] = otherCorner;
  1755. pArcPts[1] = center;
  1756. pArcPts[2] = corner;
  1757. /* convert semicircle to a polyline, and fill */
  1758. if ((cpt = miGetArcPts (&arc, 3, &pArcPts)))
  1759. /* by drawing with miFillSppPoly and setting the endpoints of the
  1760. arc to be the corners, we ensure that the cap will meet up with
  1761. the rest of the line */
  1762. miFillSppPoly (paintedSet, pixel,
  1763. cpt, pArcPts, xOrg, yOrg, xFtrans, yFtrans);
  1764. free (pArcPts);
  1765. break;
  1766. }
  1767. }
  1768. /* helper function, used by miArcJoin() above */
  1769. static double
  1770. angleBetween (SppPoint center, SppPoint point1, SppPoint point2)
  1771. {
  1772. double a1, a2, a;
  1773. /*
  1774. * reflect from X coordinates back to ellipse
  1775. * coordinates -- y increasing upwards
  1776. */
  1777. a1 = miDatan2 (- (point1.y - center.y), point1.x - center.x);
  1778. a2 = miDatan2 (- (point2.y - center.y), point2.x - center.x);
  1779. a = a2 - a1;
  1780. if (a <= -180.0)
  1781. a += 360.0;
  1782. else if (a > 180.0)
  1783. a -= 360.0;
  1784. return a;
  1785. }
  1786. /* helper function, used by miArcJoin() above */
  1787. static void
  1788. translateBounds (miArcFace *b, int x, int y, double fx, double fy)
  1789. {
  1790. fx += x;
  1791. fy += y;
  1792. b->clock.x -= fx;
  1793. b->clock.y -= fy;
  1794. b->center.x -= fx;
  1795. b->center.y -= fy;
  1796. b->counterClock.x -= fx;
  1797. b->counterClock.y -= fy;
  1798. }
  1799. /* Draw a cap on an arc segment, by calling miFillSppPoly(). */
  1800. /*ARGSUSED*/
  1801. static void
  1802. miArcCap (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, const miArcFace *pFace, int end, int xOrg, int yOrg, double xFtrans, double yFtrans)
  1803. {
  1804. SppPoint corner, otherCorner, center, endPoint, poly[5];
  1805. corner = pFace->clock;
  1806. otherCorner = pFace->counterClock;
  1807. center = pFace->center;
  1808. switch (pGC->capStyle)
  1809. {
  1810. case MI_CAP_BUTT:
  1811. case MI_CAP_NOT_LAST:
  1812. default:
  1813. break; /* do nothing */
  1814. case MI_CAP_PROJECTING:
  1815. poly[0].x = otherCorner.x;
  1816. poly[0].y = otherCorner.y;
  1817. poly[1].x = corner.x;
  1818. poly[1].y = corner.y;
  1819. poly[2].x = corner.x - (center.y - corner.y);
  1820. poly[2].y = corner.y + (center.x - corner.x);
  1821. poly[3].x = otherCorner.x - (otherCorner.y - center.y);
  1822. poly[3].y = otherCorner.y + (otherCorner.x - center.x);
  1823. poly[4].x = otherCorner.x;
  1824. poly[4].y = otherCorner.y;
  1825. miFillSppPoly (paintedSet, pixel,
  1826. 5, poly, xOrg, yOrg, xFtrans, yFtrans);
  1827. break;
  1828. case MI_CAP_TRIANGULAR:
  1829. poly[0].x = otherCorner.x;
  1830. poly[0].y = otherCorner.y;
  1831. poly[1].x = corner.x;
  1832. poly[1].y = corner.y;
  1833. poly[2].x = center.x - 0.5 * (otherCorner.y - corner.y);
  1834. poly[2].y = center.y + 0.5 * (otherCorner.x - corner.x);
  1835. poly[3].x = otherCorner.x;
  1836. poly[3].y = otherCorner.y;
  1837. miFillSppPoly (paintedSet, pixel,
  1838. 4, poly, xOrg, yOrg, xFtrans, yFtrans);
  1839. break;
  1840. case MI_CAP_ROUND:
  1841. /*
  1842. * miRoundCap() just needs these to be unequal.
  1843. */
  1844. endPoint = center;
  1845. endPoint.x = endPoint.x + 100;
  1846. miRoundCap (paintedSet, pixel, pGC,
  1847. center, endPoint, corner, otherCorner, 0,
  1848. -xOrg, -yOrg, xFtrans, yFtrans);
  1849. break;
  1850. }
  1851. }
  1852. /* MIROUNDCAP -- a helper function used by miArcCap() above.
  1853. * Put Rounded cap on end. pCenter is the center of this end of the line
  1854. * pEnd is the center of the other end of the line. pCorner is one of the
  1855. * two corners at this end of the line.
  1856. * NOTE: pOtherCorner must be counter-clockwise from pCorner.
  1857. */
  1858. /*ARGSUSED*/
  1859. static void
  1860. miRoundCap (miPaintedSet *paintedSet, miPixel pixel, const miGC *pGC, SppPoint pCenter, SppPoint pEnd, SppPoint pCorner, SppPoint pOtherCorner, int fLineEnd, int xOrg, int yOrg, double xFtrans, double yFtrans)
  1861. {
  1862. int cpt;
  1863. double width;
  1864. SppArc arc;
  1865. SppPoint *pArcPts;
  1866. width = (pGC->lineWidth ? pGC->lineWidth : 1);
  1867. arc.x = pCenter.x - width/2;
  1868. arc.y = pCenter.y - width/2;
  1869. arc.width = width;
  1870. arc.height = width;
  1871. arc.angle1 = -miDatan2 (pCorner.y - pCenter.y, pCorner.x - pCenter.x);
  1872. if (PTISEQUAL(pCenter, pEnd))
  1873. arc.angle2 = - 180.0;
  1874. else
  1875. {
  1876. arc.angle2 = -miDatan2 (pOtherCorner.y - pCenter.y, pOtherCorner.x - pCenter.x) - arc.angle1;
  1877. if (arc.angle2 < 0)
  1878. arc.angle2 += 360.0;
  1879. }
  1880. /* convert semicircle to a polyline, and fill */
  1881. pArcPts = (SppPoint *)NULL;
  1882. if ((cpt = miGetArcPts (&arc, 0, &pArcPts)))
  1883. /* by drawing with miFillSppPoly and setting the endpoints of the arc
  1884. * to be the corners, we assure that the cap will meet up with the
  1885. * rest of the line */
  1886. miFillSppPoly (paintedSet, pixel,
  1887. cpt, pArcPts, -xOrg, -yOrg, xFtrans, yFtrans);
  1888. free (pArcPts);
  1889. }
  1890. /* MIGETARCPTS -- Converts an arc into a set of line segments, so the
  1891. * resulting polygon can be filled -- a helper routine for drawing round
  1892. * joins and caps. Returns the number of points in the arc. Note that it
  1893. * takes a pointer to a pointer to where it should put the points and an
  1894. * index (cpt). This procedure allocates the space necessary to fit the
  1895. * arc points. Sometimes it's convenient for those points to be at the end
  1896. * of an existing array. (For example, if we want to leave a spare point to
  1897. * make sectors instead of segments.) So we pass in the malloc'ed chunk
  1898. * that contains the array, and an index saying where we should start
  1899. * stashing the points. If there isn't an array already, we just pass in a
  1900. * null pointer and count on mi_xrealloc() to handle the null pointer
  1901. * correctly. */
  1902. /* ARGS: cpt = number of points already in arc list
  1903. ppPts = ptr to ptr to arc-list -- modified */
  1904. static int
  1905. miGetArcPts (const SppArc *parc, int cpt, SppPoint **ppPts)
  1906. {
  1907. double st; /* Start Theta, start angle */
  1908. double et; /* End Theta, offset from start theta */
  1909. double dt; /* Delta Theta, angle to sweep ellipse */
  1910. double cdt; /* Cos Delta Theta, actually 2 cos(dt) */
  1911. double x0, y0; /* recurrence formula needs 2 points to start*/
  1912. double x1, y1;
  1913. double x2, y2; /* this will be the new point generated */
  1914. double xc, yc; /* the center point */
  1915. int count, i;
  1916. SppPoint *poly;
  1917. miPoint last; /* last point on integer boundaries */
  1918. /* The spec says that positive angles indicate counterclockwise motion.
  1919. Given our coordinate system (with 0,0 in the upper left corner), the
  1920. screen appears flipped in Y. The easiest fix is to negate the angles
  1921. given. */
  1922. st = - parc->angle1;
  1923. et = - parc->angle2;
  1924. /* Try to get a delta theta that is within 1/2 pixel. Then adjust it
  1925. * so that it divides evenly into the total.
  1926. * I'm just using cdt 'cause I'm lazy.
  1927. */
  1928. cdt = parc->width;
  1929. if (parc->height > cdt)
  1930. cdt = parc->height;
  1931. cdt *= 0.5;
  1932. if (cdt <= 0)
  1933. return 0;
  1934. if (cdt < 1.0)
  1935. cdt = 1.0;
  1936. dt = miDasin (1.0 / cdt); /* minimum step necessary */
  1937. count = (int)(et/dt);
  1938. count = abs(count) + 1;
  1939. dt = et/count;
  1940. count++;
  1941. cdt = 2 * miDcos(dt);
  1942. poly = (SppPoint *) mi_xrealloc(*ppPts,
  1943. (cpt + count) * sizeof(SppPoint));
  1944. *ppPts = poly;
  1945. xc = 0.5 * parc->width; /* store half width and half height */
  1946. yc = 0.5 * parc->height;
  1947. x0 = xc * miDcos(st);
  1948. y0 = yc * miDsin(st);
  1949. x1 = xc * miDcos(st + dt);
  1950. y1 = yc * miDsin(st + dt);
  1951. xc += parc->x; /* by adding initial point, these become */
  1952. yc += parc->y; /* the center point */
  1953. poly[cpt].x = (xc + x0);
  1954. poly[cpt].y = (yc + y0);
  1955. poly[cpt + 1].x = (xc + x1);
  1956. poly[cpt + 1].y = (yc + y1);
  1957. last.x = IROUND(xc + x1);
  1958. last.y = IROUND(yc + y1);
  1959. for (i = 2; i < count; i++)
  1960. {
  1961. x2 = cdt * x1 - x0;
  1962. y2 = cdt * y1 - y0;
  1963. poly[cpt + i].x = (xc + x2);
  1964. poly[cpt + i].y = (yc + y2);
  1965. x0 = x1; y0 = y1;
  1966. x1 = x2; y1 = y2;
  1967. }
  1968. /* adjust the last point */
  1969. if (FABS(parc->angle2) >= 360.0)
  1970. poly[cpt +i -1] = poly[0];
  1971. else
  1972. {
  1973. poly[cpt +i -1].x = (miDcos(st + et) * 0.5 * parc->width + xc);
  1974. poly[cpt +i -1].y = (miDsin(st + et) * 0.5 * parc->height + yc);
  1975. }
  1976. return count;
  1977. }
  1978. /**********************************************************************/
  1979. /* Specially defined trig functions. At the cardinal points, they are
  1980. exact. */
  1981. /**********************************************************************/
  1982. #define Dsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
  1983. #define Dcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
  1984. #define mod(a,b) ((a) >= 0 ? (a) % (b) : (b) - (-a) % (b))
  1985. static double
  1986. miDcos (double a)
  1987. {
  1988. int i;
  1989. if (floor (a/90) == a/90)
  1990. {
  1991. i = (int) (a/90.0);
  1992. switch (mod (i, 4))
  1993. {
  1994. case 0: return 1;
  1995. case 1: return 0;
  1996. case 2: return -1;
  1997. case 3: return 0;
  1998. }
  1999. }
  2000. return cos (a * M_PI / 180.0);
  2001. }
  2002. static double
  2003. miDsin (double a)
  2004. {
  2005. int i;
  2006. if (floor (a/90) == a/90)
  2007. {
  2008. i = (int) (a/90.0);
  2009. switch (mod (i, 4))
  2010. {
  2011. case 0: return 0;
  2012. case 1: return 1;
  2013. case 2: return 0;
  2014. case 3: return -1;
  2015. }
  2016. }
  2017. return sin (a * M_PI / 180.0);
  2018. }
  2019. static double
  2020. miDasin (double v)
  2021. {
  2022. if (v == 0)
  2023. return 0.0;
  2024. if (v == 1.0)
  2025. return 90.0;
  2026. if (v == -1.0)
  2027. return -90.0;
  2028. return asin(v) * (180.0 / M_PI);
  2029. }
  2030. static double
  2031. miDatan2 (double dy, double dx)
  2032. {
  2033. if (dy == 0)
  2034. {
  2035. if (dx >= 0)
  2036. return 0.0;
  2037. return 180.0;
  2038. }
  2039. else if (dx == 0)
  2040. {
  2041. if (dy > 0)
  2042. return 90.0;
  2043. return -90.0;
  2044. }
  2045. else if (FABS(dy) == FABS(dx))
  2046. {
  2047. if (dy > 0)
  2048. {
  2049. if (dx > 0)
  2050. return 45.0;
  2051. return 135.0;
  2052. }
  2053. else
  2054. {
  2055. if (dx > 0)
  2056. return 315.0;
  2057. return 225.0;
  2058. }
  2059. }
  2060. else
  2061. return atan2 (dy, dx) * (180.0 / M_PI);
  2062. }
  2063. /***********************************************************************/
  2064. /* A sub-module that computes arc lengths via a polygonal approximation to
  2065. * the arc. External functions are computeDashMap(), which should be
  2066. * called first, and the primary function computeAngleFromPath(). They are
  2067. * called by miComputeArcs() above. */
  2068. /***********************************************************************/
  2069. #define dashIndexToAngle(di) ((((double) (di)) * 90.0) / ((double) DASH_MAP_SIZE - 1))
  2070. #define xAngleToDashIndex(xa) ((((long) (xa)) * (DASH_MAP_SIZE - 1)) / (90 * 64))
  2071. #define dashIndexToXAngle(di) ((((long) (di)) * (90 * 64)) / (DASH_MAP_SIZE - 1))
  2072. #define dashXAngleStep (((double) (90 * 64)) / ((double) (DASH_MAP_SIZE - 1)))
  2073. /* forward references (functions in this sub-module) */
  2074. static double angleToLength (int angle, const dashMap *map);
  2075. static int lengthToAngle (double len, const dashMap *map);
  2076. static void
  2077. computeDashMap (const miArc *arcp, dashMap *map)
  2078. {
  2079. int di;
  2080. double a, x, y, prevx = 0.0, prevy = 0.0, dist;
  2081. for (di = 0; di < DASH_MAP_SIZE; di++)
  2082. {
  2083. a = dashIndexToAngle (di);
  2084. x = (double)(0.5 * arcp->width) * miDcos (a);
  2085. y = (double)(0.5 * arcp->height) * miDsin (a);
  2086. if (di == 0)
  2087. map->map[di] = 0.0;
  2088. else
  2089. {
  2090. dist = hypot (x - prevx, y - prevy);
  2091. map->map[di] = map->map[di - 1] + dist;
  2092. }
  2093. prevx = x;
  2094. prevy = y;
  2095. }
  2096. }
  2097. static double
  2098. angleToLength (int angle, const dashMap *map)
  2099. {
  2100. double len, excesslen, sidelen = map->map[DASH_MAP_SIZE - 1], totallen;
  2101. int di;
  2102. int excess;
  2103. bool oddSide = false;
  2104. totallen = 0;
  2105. if (angle >= 0)
  2106. {
  2107. while (angle >= 90 * 64)
  2108. {
  2109. angle -= 90 * 64;
  2110. totallen += sidelen;
  2111. oddSide = (oddSide ? false : true);
  2112. }
  2113. }
  2114. else
  2115. {
  2116. while (angle < 0)
  2117. {
  2118. angle += 90 * 64;
  2119. totallen -= sidelen;
  2120. oddSide = (oddSide ? false : true);
  2121. }
  2122. }
  2123. if (oddSide)
  2124. angle = 90 * 64 - angle;
  2125. di = xAngleToDashIndex (angle);
  2126. excess = angle - dashIndexToXAngle (di);
  2127. len = map->map[di];
  2128. /*
  2129. * linearly interpolate between this point and the next
  2130. */
  2131. if (excess > 0)
  2132. {
  2133. excesslen = (map->map[di + 1] - map->map[di]) *
  2134. ((double) excess) / dashXAngleStep;
  2135. len += excesslen;
  2136. }
  2137. if (oddSide)
  2138. totallen += (sidelen - len);
  2139. else
  2140. totallen += len;
  2141. return totallen;
  2142. }
  2143. /*
  2144. * len is along the arc, but may be more than one rotation
  2145. */
  2146. static int
  2147. lengthToAngle (double len, const dashMap *map)
  2148. {
  2149. double sidelen = map->map[DASH_MAP_SIZE - 1];
  2150. int angle, angleexcess;
  2151. bool oddSide = false;
  2152. int a0, a1, a;
  2153. angle = 0;
  2154. /*
  2155. * step around the ellipse, subtracting sidelens and
  2156. * adding 90 degrees. oddSide will tell if the
  2157. * map should be interpolated in reverse
  2158. */
  2159. if (len >= 0)
  2160. {
  2161. if (sidelen == 0)
  2162. return 2 * FULLCIRCLE; /* infinity */
  2163. while (len >= sidelen)
  2164. {
  2165. angle += 90 * 64;
  2166. len -= sidelen;
  2167. oddSide = (oddSide ? false : true);
  2168. }
  2169. }
  2170. else
  2171. {
  2172. if (sidelen == 0)
  2173. return -2 * FULLCIRCLE; /* infinity */
  2174. while (len < 0)
  2175. {
  2176. angle -= 90 * 64;
  2177. len += sidelen;
  2178. oddSide = (oddSide ? false : true);
  2179. }
  2180. }
  2181. if (oddSide)
  2182. len = sidelen - len;
  2183. a0 = 0;
  2184. a1 = DASH_MAP_SIZE - 1;
  2185. /*
  2186. * binary search for the closest pre-computed length
  2187. */
  2188. while (a1 - a0 > 1)
  2189. {
  2190. a = (a0 + a1) / 2;
  2191. if (len > map->map[a])
  2192. a0 = a;
  2193. else
  2194. a1 = a;
  2195. }
  2196. angleexcess = dashIndexToXAngle (a0);
  2197. /*
  2198. * linearly interpolate to the next point
  2199. */
  2200. angleexcess += (int)((len - map->map[a0]) /
  2201. (map->map[a0+1] - map->map[a0]) * dashXAngleStep);
  2202. if (oddSide)
  2203. angle += (90 * 64) - angleexcess;
  2204. else
  2205. angle += angleexcess;
  2206. return angle;
  2207. }
  2208. /* Compute the subtended angle, in 1/64 degree units, of an elliptic arc
  2209. * that corresponds to a specified dash length. The correct solution to
  2210. * this problem involves an elliptic integral, so we punt by approximating
  2211. * (it's only for dashes anyway...). The approximation uses a polygon.
  2212. *
  2213. * The specified dash length `len' is updated, to equal the amount of the
  2214. * dash that will remain after drawing the arc. This may be nonzero due to
  2215. * rounding. The new value will be negative if the arc extends beyond the
  2216. * specified dash length, and positive if the specified dash length extends
  2217. * beyond the arc. */
  2218. static int
  2219. computeAngleFromPath (int startAngle, int endAngle, const dashMap *map, int *lenp, bool backwards)
  2220. /* start, endAngle are angles in 1/64 degree units */
  2221. {
  2222. int a0, a1, a;
  2223. double len0;
  2224. int len;
  2225. a0 = startAngle;
  2226. a1 = endAngle;
  2227. len = *lenp;
  2228. if (backwards)
  2229. /* flip the problem around to be forwards */
  2230. {
  2231. a0 = FULLCIRCLE - a0;
  2232. a1 = FULLCIRCLE - a1;
  2233. }
  2234. if (a1 < a0)
  2235. a1 += FULLCIRCLE;
  2236. len0 = angleToLength (a0, map);
  2237. a = lengthToAngle (len0 + len, map);
  2238. if (a > a1)
  2239. {
  2240. a = a1;
  2241. len = (int)(len - angleToLength (a1, map) - len0);
  2242. }
  2243. else
  2244. len = 0;
  2245. if (backwards)
  2246. a = FULLCIRCLE - a;
  2247. *lenp = len;
  2248. return a;
  2249. }
  2250. /***********************************************************************/
  2251. /* Geometry computations related to wide ellipses, e.g., computeAcc(),
  2252. which computes `accelerators' (frequently used quantities), and
  2253. computeBounds(). */
  2254. /***********************************************************************/
  2255. /* definition of a wide arc */
  2256. struct arc_def
  2257. {
  2258. double w, h; /* half-width, half-height */
  2259. double l; /* half of line width */
  2260. double a0, a1; /* start angle, and angle range */
  2261. };
  2262. struct bound
  2263. {
  2264. double min, max;
  2265. };
  2266. struct ibound
  2267. {
  2268. int min, max;
  2269. };
  2270. /*
  2271. * These are all y value bounds; computed by computeBounds().
  2272. */
  2273. struct arc_bound
  2274. {
  2275. struct bound ellipse;
  2276. struct bound inner, outer;
  2277. struct bound right, left;
  2278. struct ibound inneri, outeri;
  2279. };
  2280. struct line
  2281. {
  2282. double m, b; /* for y = mx + b */
  2283. bool valid;
  2284. };
  2285. /* Quantities frequently used when drawn an ellipse or elliptic arc;
  2286. computed by computeAcc(). */
  2287. struct accelerators
  2288. {
  2289. double tail_y; /* "y value associated with bottom of tail" */
  2290. double h2; /* half-height squared */
  2291. double w2; /* half-width squared */
  2292. double h4; /* half-height raised to 4th power */
  2293. double w4; /* half-width raised to 4th power */
  2294. double h2mw2; /* h2 minus w2 */
  2295. double h2l; /* h2 times l (i.e. half the line width) */
  2296. double w2l; /* w2 times l (i.e. half the line width) */
  2297. double fromIntX; /* 0.5 if width is odd, otherwise 0.0 */
  2298. double fromIntY; /* 0.5 if height is oddd, otherwise 0.0 */
  2299. struct line left, right;
  2300. int yorgu;
  2301. int yorgl;
  2302. int xorg;
  2303. };
  2304. #define boundedLe(value, bounds)\
  2305. ((bounds).min <= (value) && (value) <= (bounds).max)
  2306. #define intersectLine(y,line) (line.m * (y) + line.b)
  2307. /* forward references */
  2308. static double hookEllipseY (double scan_y, const struct arc_bound *bound, const struct accelerators *acc, bool left);
  2309. static double hookX (double scan_y, const struct arc_def *def, const struct arc_bound *bound, const struct accelerators *acc, bool left);
  2310. static double innerXfromXY (double x, double y, const struct accelerators *acc);
  2311. static double innerYfromXY (double x, double y, const struct accelerators *acc);
  2312. static double innerYfromY (double y, const struct arc_def *def, const struct accelerators *acc);
  2313. static double outerXfromXY (double x, double y, const struct accelerators *acc);
  2314. static double outerYfromXY (double x, double y, const struct accelerators *acc);
  2315. static double tailX (double K, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc);
  2316. static void computeAcc (const miArc *tarc, unsigned int lw, struct arc_def *def, struct accelerators *acc);
  2317. static void computeBound (const struct arc_def *def, struct arc_bound *bound, struct accelerators *acc, miArcFace *right, miArcFace *left);
  2318. static void computeLine (double x1, double y1, double x2, double y2, struct line *line);
  2319. static void tailEllipseY (const struct arc_def *def, struct accelerators *acc);
  2320. static double
  2321. tailX (double K, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc)
  2322. {
  2323. double w, h, r;
  2324. double Hs, Hf, WH, Vk, Nk, Fk, Vr, N, Nc, Z, rs;
  2325. double A, T, b, d, x, y, t, hepp, hepm;
  2326. int flip, solution;
  2327. double xs[2];
  2328. double *xp;
  2329. w = def->w;
  2330. h = def->h;
  2331. r = def->l;
  2332. rs = r * r;
  2333. Hs = acc->h2;
  2334. WH = -acc->h2mw2;
  2335. Nk = def->w * r;
  2336. Vk = (Nk * Hs) / (WH + WH);
  2337. Hf = acc->h4;
  2338. Nk = (Hf - Nk * Nk) / WH;
  2339. if (K == 0.0)
  2340. {
  2341. if (Nk < 0.0 && -Nk < Hs)
  2342. {
  2343. xs[0] = w * sqrt(1 + Nk / Hs) - sqrt(rs + Nk);
  2344. xs[1] = w - r;
  2345. if (acc->left.valid && boundedLe(K, bounds->left) &&
  2346. !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
  2347. return xs[1];
  2348. if (acc->right.valid && boundedLe(K, bounds->right) &&
  2349. !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
  2350. return xs[1];
  2351. return xs[0];
  2352. }
  2353. return w - r;
  2354. }
  2355. Fk = Hf / WH;
  2356. hepp = h + EPSILON;
  2357. hepm = h - EPSILON;
  2358. N = (K * K + Nk) / 6.0;
  2359. Nc = N * N * N;
  2360. Vr = Vk * K;
  2361. xp = xs;
  2362. xs[0] = 0.0;
  2363. t = Nc + Vr * Vr;
  2364. d = Nc + t;
  2365. if (d < 0.0)
  2366. {
  2367. d = Nc;
  2368. b = N;
  2369. if ( (b < 0.0) == (t < 0.0) )
  2370. {
  2371. b = -b;
  2372. d = -d;
  2373. }
  2374. Z = N - 2.0 * b * cos (acos (-t / d) / 3.0);
  2375. if ( (Z < 0.0) == (Vr < 0.0) )
  2376. flip = 2;
  2377. else
  2378. flip = 1;
  2379. }
  2380. else
  2381. {
  2382. d = Vr * sqrt (d);
  2383. Z = N + cbrt (t + d) + cbrt (t - d);
  2384. flip = 0;
  2385. }
  2386. A = sqrt ((Z + Z) - Nk);
  2387. T = (Fk - Z) * K / A;
  2388. solution = false;
  2389. b = -A + K;
  2390. d = b * b - 4 * (Z + T);
  2391. if (d >= 0 && flip == 2)
  2392. {
  2393. d = sqrt(d);
  2394. y = 0.5 * (b + d);
  2395. if ((y >= 0.0) && (y < hepp))
  2396. {
  2397. solution = true;
  2398. if (y > hepm)
  2399. y = h;
  2400. t = y / h;
  2401. x = w * sqrt(1 - (t * t));
  2402. t = K - y;
  2403. t = sqrt(rs - (t * t));
  2404. *xp++ = x - t;
  2405. }
  2406. }
  2407. b = A + K;
  2408. d = b * b - 4 * (Z - T);
  2409. /* Because of the large magnitudes involved, we lose enough precision
  2410. * that sometimes we end up with a negative value near the axis, when
  2411. * it should be positive. This is a workaround.
  2412. */
  2413. if (d < 0 && !solution)
  2414. d = 0.0;
  2415. if (d >= 0)
  2416. {
  2417. d = sqrt(d);
  2418. y = 0.5 * (b + d);
  2419. if (y < hepp)
  2420. {
  2421. if (y > hepm)
  2422. y = h;
  2423. t = y / h;
  2424. x = w * sqrt(1 - (t * t));
  2425. t = K - y;
  2426. *xp++ = x - sqrt(rs - (t * t));
  2427. }
  2428. y = 0.5 * (b - d);
  2429. if (y >= 0.0 && flip == 1)
  2430. {
  2431. if (y > hepm)
  2432. y = h;
  2433. t = y / h;
  2434. x = w * sqrt(1 - (t * t));
  2435. t = K - y;
  2436. t = sqrt(rs - (t * t));
  2437. *xp++ = x - t;
  2438. }
  2439. }
  2440. if (xp > &xs[1])
  2441. {
  2442. if (acc->left.valid && boundedLe(K, bounds->left) &&
  2443. !boundedLe(K, bounds->outer) && xs[0] >= 0.0 && xs[1] >= 0.0)
  2444. return xs[1];
  2445. if (acc->right.valid && boundedLe(K, bounds->right) &&
  2446. !boundedLe(K, bounds->inner) && xs[0] <= 0.0 && xs[1] <= 0.0)
  2447. return xs[1];
  2448. }
  2449. return xs[0];
  2450. }
  2451. /*
  2452. * This computes the ellipse y value associated with the
  2453. * bottom of the tail.
  2454. */
  2455. #define CUBE_ROOT_2 1.2599210498948732038115849718451499938964
  2456. #define CUBE_ROOT_4 1.5874010519681993173435330390930175781250
  2457. static void
  2458. tailEllipseY (const struct arc_def *def, struct accelerators *acc)
  2459. {
  2460. double t;
  2461. acc->tail_y = 0.0;
  2462. if (def->w == def->h)
  2463. return;
  2464. t = def->l * def->w;
  2465. if (def->w > def->h)
  2466. {
  2467. if (t < acc->h2)
  2468. return;
  2469. }
  2470. else
  2471. {
  2472. if (t > acc->h2)
  2473. return;
  2474. }
  2475. t = 2.0 * def->h * t;
  2476. t = (CUBE_ROOT_4 * acc->h2 - cbrt(t * t)) / acc->h2mw2;
  2477. if (t > 0.0)
  2478. acc->tail_y = def->h / CUBE_ROOT_2 * sqrt(t);
  2479. }
  2480. /*
  2481. * inverse functions -- compute edge coordinates
  2482. * from the ellipse (actually, from its precomputed accelerators)
  2483. */
  2484. static double
  2485. outerXfromXY (double x, double y, const struct accelerators *acc)
  2486. {
  2487. return x + (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
  2488. }
  2489. static double
  2490. outerYfromXY (double x, double y, const struct accelerators *acc)
  2491. {
  2492. return y + (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
  2493. }
  2494. static double
  2495. innerXfromXY (double x, double y, const struct accelerators *acc)
  2496. {
  2497. return x - (x * acc->h2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
  2498. }
  2499. static double
  2500. innerYfromXY (double x, double y, const struct accelerators *acc)
  2501. {
  2502. return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
  2503. }
  2504. static double
  2505. innerYfromY (double y, const struct arc_def *def, const struct accelerators *acc)
  2506. {
  2507. double x;
  2508. x = (def->w / def->h) * sqrt (acc->h2 - y*y);
  2509. return y - (y * acc->w2l) / sqrt (x*x * acc->h4 + y*y * acc->w4);
  2510. }
  2511. /* compute a line through two points */
  2512. static void
  2513. computeLine (double x1, double y1, double x2, double y2, struct line *line)
  2514. {
  2515. if (y1 == y2)
  2516. line->valid = false;
  2517. else
  2518. {
  2519. line->m = (x1 - x2) / (y1 - y2);
  2520. line->b = x1 - y1 * line->m;
  2521. line->valid = true;
  2522. }
  2523. }
  2524. /* Compute accelerators for an ellipse. These are simply values that are
  2525. used repeatedly in the computations. Also begin filling in the arc_def
  2526. structure too. */
  2527. static void
  2528. computeAcc (const miArc *tarc, unsigned int lw, struct arc_def *def, struct accelerators *acc)
  2529. {
  2530. def->w = 0.5 * (double)tarc->width;
  2531. def->h = 0.5 * (double)tarc->height;
  2532. def->l = 0.5 * (double)lw;
  2533. acc->h2 = def->h * def->h;
  2534. acc->w2 = def->w * def->w;
  2535. acc->h4 = acc->h2 * acc->h2;
  2536. acc->w4 = acc->w2 * acc->w2;
  2537. acc->h2l = acc->h2 * def->l;
  2538. acc->w2l = acc->w2 * def->l;
  2539. acc->h2mw2 = acc->h2 - acc->w2;
  2540. acc->fromIntX = (tarc->width & 1) ? 0.5 : 0.0;
  2541. acc->fromIntY = (tarc->height & 1) ? 0.5 : 0.0;
  2542. acc->xorg = tarc->x + (int)(tarc->width >> 1);
  2543. acc->yorgu = tarc->y + (int)(tarc->height >> 1);
  2544. acc->yorgl = acc->yorgu + (tarc->height & 1);
  2545. tailEllipseY (def, acc); /* fill in tail_y element of acc */
  2546. }
  2547. /* Compute y value bounds of various portions of the arc, the outer edge,
  2548. the ellipse and the inner edge. Also invoke computeLine to compute left
  2549. and right lines (stored in accelerator structure). */
  2550. static void
  2551. computeBound (const struct arc_def *def, struct arc_bound *bound, struct accelerators *acc, miArcFace *right, miArcFace *left)
  2552. {
  2553. double t;
  2554. double innerTaily;
  2555. double tail_y;
  2556. struct bound innerx, outerx;
  2557. struct bound ellipsex;
  2558. bound->ellipse.min = Dsin (def->a0) * def->h;
  2559. bound->ellipse.max = Dsin (def->a1) * def->h;
  2560. if (def->a0 == 45 && def->w == def->h)
  2561. ellipsex.min = bound->ellipse.min;
  2562. else
  2563. ellipsex.min = Dcos (def->a0) * def->w;
  2564. if (def->a1 == 45 && def->w == def->h)
  2565. ellipsex.max = bound->ellipse.max;
  2566. else
  2567. ellipsex.max = Dcos (def->a1) * def->w;
  2568. bound->outer.min = outerYfromXY (ellipsex.min, bound->ellipse.min, acc);
  2569. bound->outer.max = outerYfromXY (ellipsex.max, bound->ellipse.max, acc);
  2570. bound->inner.min = innerYfromXY (ellipsex.min, bound->ellipse.min, acc);
  2571. bound->inner.max = innerYfromXY (ellipsex.max, bound->ellipse.max, acc);
  2572. outerx.min = outerXfromXY (ellipsex.min, bound->ellipse.min, acc);
  2573. outerx.max = outerXfromXY (ellipsex.max, bound->ellipse.max, acc);
  2574. innerx.min = innerXfromXY (ellipsex.min, bound->ellipse.min, acc);
  2575. innerx.max = innerXfromXY (ellipsex.max, bound->ellipse.max, acc);
  2576. /* Save the line end points for the cap code to use. Careful here, these
  2577. * are in Cartesian coordinates (y increasing upwards) while the cap code
  2578. * uses inverted coordinates (y increasing downwards).
  2579. */
  2580. if (right)
  2581. {
  2582. right->counterClock.y = bound->outer.min;
  2583. right->counterClock.x = outerx.min;
  2584. right->center.y = bound->ellipse.min;
  2585. right->center.x = ellipsex.min;
  2586. right->clock.y = bound->inner.min;
  2587. right->clock.x = innerx.min;
  2588. }
  2589. if (left)
  2590. {
  2591. left->clock.y = bound->outer.max;
  2592. left->clock.x = outerx.max;
  2593. left->center.y = bound->ellipse.max;
  2594. left->center.x = ellipsex.max;
  2595. left->counterClock.y = bound->inner.max;
  2596. left->counterClock.x = innerx.max;
  2597. }
  2598. bound->left.min = bound->inner.max;
  2599. bound->left.max = bound->outer.max;
  2600. bound->right.min = bound->inner.min;
  2601. bound->right.max = bound->outer.min;
  2602. computeLine (innerx.min, bound->inner.min, outerx.min, bound->outer.min,
  2603. &acc->right);
  2604. computeLine (innerx.max, bound->inner.max, outerx.max, bound->outer.max,
  2605. &acc->left);
  2606. if (bound->inner.min > bound->inner.max)
  2607. {
  2608. t = bound->inner.min;
  2609. bound->inner.min = bound->inner.max;
  2610. bound->inner.max = t;
  2611. }
  2612. tail_y = acc->tail_y;
  2613. if (tail_y > bound->ellipse.max)
  2614. tail_y = bound->ellipse.max;
  2615. else if (tail_y < bound->ellipse.min)
  2616. tail_y = bound->ellipse.min;
  2617. innerTaily = innerYfromY (tail_y, def, acc);
  2618. if (bound->inner.min > innerTaily)
  2619. bound->inner.min = innerTaily;
  2620. if (bound->inner.max < innerTaily)
  2621. bound->inner.max = innerTaily;
  2622. bound->inneri.min = ICEIL(bound->inner.min - acc->fromIntY);
  2623. bound->inneri.max = IFLOOR(bound->inner.max - acc->fromIntY);
  2624. bound->outeri.min = ICEIL(bound->outer.min - acc->fromIntY);
  2625. bound->outeri.max = IFLOOR(bound->outer.max - acc->fromIntY);
  2626. }
  2627. /*
  2628. * this section computes the x value of the span at y
  2629. * intersected with the specified face of the ellipse.
  2630. *
  2631. * this is the min/max X value over the set of normal
  2632. * lines to the entire ellipse, the equation of the
  2633. * normal lines is:
  2634. *
  2635. * ellipse_x h^2 h^2
  2636. * x = ------------ y + ellipse_x (1 - --- )
  2637. * ellipse_y w^2 w^2
  2638. *
  2639. * compute the derivative with-respect-to ellipse_y and solve
  2640. * for zero:
  2641. *
  2642. * (w^2 - h^2) ellipse_y^3 + h^4 y
  2643. * 0 = - ----------------------------------
  2644. * h w ellipse_y^2 sqrt (h^2 - ellipse_y^2)
  2645. *
  2646. * ( h^4 y )
  2647. * ellipse_y = ( ---------- ) ^ (1/3)
  2648. * ( (h^2 - w^2) )
  2649. *
  2650. * The other two solutions to the equation are imaginary.
  2651. *
  2652. * This gives the position on the ellipse which generates
  2653. * the normal with the largest/smallest x intersection point.
  2654. *
  2655. * Now compute the second derivative to check whether
  2656. * the intersection is a minimum or maximum:
  2657. *
  2658. * h (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
  2659. * - -------------------------------------------
  2660. * w y0^3 (sqrt (h^2 - y^2)) ^ 3
  2661. *
  2662. * as we only care about the sign,
  2663. *
  2664. * - (y0^3 (w^2 - h^2) + h^2 y (3y0^2 - 2h^2))
  2665. *
  2666. * or (to use accelerators),
  2667. *
  2668. * y0^3 (h^2 - w^2) - h^2 y (3y0^2 - 2h^2)
  2669. *
  2670. */
  2671. /* Compute the position on the ellipse whose normal line intersects the
  2672. given scan line maximally. */
  2673. static double
  2674. hookEllipseY (double scan_y, const struct arc_bound *bound, const struct accelerators *acc, bool left)
  2675. {
  2676. double ret;
  2677. if (acc->h2mw2 == 0)
  2678. {
  2679. if ( (scan_y > 0 && (left ? false : true)) || (scan_y < 0 && left) )
  2680. return bound->ellipse.min;
  2681. return bound->ellipse.max;
  2682. }
  2683. ret = (acc->h4 * scan_y) / (acc->h2mw2);
  2684. if (ret >= 0)
  2685. return cbrt (ret);
  2686. else
  2687. return -cbrt (-ret);
  2688. }
  2689. /* Compute the X value of the intersection of the given scan line with the
  2690. right side of the lower hook. */
  2691. static double
  2692. hookX (double scan_y, const struct arc_def *def, const struct arc_bound *bound, const struct accelerators *acc, bool left)
  2693. {
  2694. double ellipse_y, x;
  2695. double maxMin;
  2696. if (def->w != def->h)
  2697. {
  2698. ellipse_y = hookEllipseY (scan_y, bound, acc, left);
  2699. if (boundedLe (ellipse_y, bound->ellipse))
  2700. {
  2701. /*
  2702. * compute the value of the second
  2703. * derivative
  2704. */
  2705. maxMin = ellipse_y*ellipse_y*ellipse_y * acc->h2mw2 -
  2706. acc->h2 * scan_y * (3 * ellipse_y*ellipse_y - 2*acc->h2);
  2707. if ((left && maxMin > 0) || ((left ? false : true) && maxMin < 0))
  2708. {
  2709. if (ellipse_y == 0)
  2710. return def->w + left ? -def->l : def->l;
  2711. x = (acc->h2 * scan_y - ellipse_y * acc->h2mw2) *
  2712. sqrt (acc->h2 - ellipse_y * ellipse_y) /
  2713. (def->h * def->w * ellipse_y);
  2714. return x;
  2715. }
  2716. }
  2717. }
  2718. if (left)
  2719. {
  2720. if (acc->left.valid && boundedLe (scan_y, bound->left))
  2721. x = intersectLine (scan_y, acc->left);
  2722. else
  2723. {
  2724. if (acc->right.valid)
  2725. x = intersectLine (scan_y, acc->right);
  2726. else
  2727. x = def->w - def->l;
  2728. }
  2729. }
  2730. else
  2731. {
  2732. if (acc->right.valid && boundedLe (scan_y, bound->right))
  2733. x = intersectLine (scan_y, acc->right);
  2734. else
  2735. {
  2736. if (acc->left.valid)
  2737. x = intersectLine (scan_y, acc->left);
  2738. else
  2739. x = def->w - def->l;
  2740. }
  2741. }
  2742. return x;
  2743. }
  2744. /**********************************************************************/
  2745. /* The following three sub-modules, taken together, provide only five
  2746. public functions: initAccumSpans(), which initializes an miAccumSpans
  2747. structure, newFinalSpan(), which draws a single span to a miAccumSpans
  2748. structure, drawArc(), which draws a single arc to a miAccumSpans
  2749. structure as a collection of spans, drawZeroArc(), which draws a single
  2750. degenerate (horizontal or vertical) arc, and finally fillSpans(), which
  2751. paints the miAccumSpans structure, deallocates the spans, and resets the
  2752. structure. */
  2753. /**********************************************************************/
  2754. /**********************************************************************/
  2755. /* A sub-module that accumulates an in-core cache of spans and on request,
  2756. paints them. Only two public functions are newFinalSpan() and
  2757. fillSpans(). Former is invoked by the succeeding sub-module, which
  2758. draws arcs as spans and in turn is invoked by the drawArc() sub-module.
  2759. Latter is invoked above, in miPolyArc(), to clean things up. */
  2760. /**********************************************************************/
  2761. /* ???!!! a ceiling on amount by which finalSpans array is expanded !!!??? */
  2762. #define SPAN_REALLOC 100
  2763. /* forward references */
  2764. static struct finalSpan * realAllocSpan (miAccumSpans *accumSpans);
  2765. static struct finalSpan ** realFindSpan (miAccumSpans *accumSpans, int y);
  2766. static void disposeFinalSpans (miAccumSpans *accumSpans);
  2767. static void newFinalSpan (miAccumSpans *accumSpans, int y, int xmin, int xmax);
  2768. /*** allocation-related functions ***/
  2769. /* A public function for this module: initialize an miAccumSpans structure
  2770. (an in-core accumulation of spans, which is added to by newFinalSpan(),
  2771. and painted and deallocated by fillSpans()). */
  2772. static void
  2773. initAccumSpans (miAccumSpans *accumSpans)
  2774. {
  2775. accumSpans->finalSpans = (struct finalSpan **)NULL;
  2776. accumSpans->finalMiny = 0;
  2777. accumSpans->finalMaxy = -1;
  2778. accumSpans->finalSize = 0;
  2779. accumSpans->nspans = 0;
  2780. accumSpans->chunks = (struct finalSpanChunk *)NULL;
  2781. accumSpans->freeFinalSpans = (struct finalSpan *)NULL;
  2782. }
  2783. /* A public function for this module: add a span to an miAccumSpans
  2784. structure. By convention, span is [xmin, xmax-1] in terms of pixels.
  2785. This agrees with the libxmi convention that `right edges' (as well as
  2786. bottom edges) of polygons should be omitted, so that adjacent polygons
  2787. can abut with no overlaps or gaps. */
  2788. static void
  2789. newFinalSpan (miAccumSpans *accumSpans, int y, int xmin, int xmax)
  2790. {
  2791. struct finalSpan *x, *oldx, *prev, **f;
  2792. /* find list of spans at this value of y in finalSpans array; if y isn't
  2793. in the range finalMiny..finalMaxy, invoke realFindSpan() to expand
  2794. finalSpans array */
  2795. if (accumSpans->finalMiny <= y && y <= accumSpans->finalMaxy)
  2796. f = &((accumSpans->finalSpans)[(y) - (accumSpans->finalMiny)]);
  2797. else
  2798. f = realFindSpan (accumSpans, y);
  2799. /* loop through spans at y, trying to expand an existing one */
  2800. if (f == (struct finalSpan **)NULL)
  2801. return;
  2802. oldx = (struct finalSpan *)NULL;
  2803. for (;;)
  2804. {
  2805. prev = (struct finalSpan *)NULL;
  2806. for (x = *f; x; x = x->next)
  2807. {
  2808. if (x == oldx)
  2809. {
  2810. prev = x;
  2811. continue;
  2812. }
  2813. if (x->min <= xmax && xmin <= x->max)
  2814. /* expand span */
  2815. {
  2816. if (oldx)
  2817. {
  2818. oldx->min = IMIN (x->min, xmin);
  2819. oldx->max = IMAX (x->max, xmax);
  2820. if (prev)
  2821. prev->next = x->next;
  2822. else
  2823. *f = x->next;
  2824. --(accumSpans->nspans);
  2825. }
  2826. else
  2827. {
  2828. x->min = IMIN (x->min, xmin);
  2829. x->max = IMAX (x->max, xmax);
  2830. oldx = x;
  2831. }
  2832. xmin = oldx->min;
  2833. xmax = oldx->max;
  2834. break;
  2835. }
  2836. prev = x;
  2837. }
  2838. if (!x)
  2839. break;
  2840. }
  2841. if (!oldx)
  2842. /* couldn't expand an existing span at this value of y, so create a new
  2843. one and add it to the list */
  2844. {
  2845. /* obtain new span from current chunk; if chunk is exhausted, invoke
  2846. realAllocSpan() to allocate a new one */
  2847. if (accumSpans->freeFinalSpans != (struct finalSpan *)NULL)
  2848. {
  2849. x = accumSpans->freeFinalSpans;
  2850. accumSpans->freeFinalSpans = accumSpans->freeFinalSpans->next;
  2851. x->next = (struct finalSpan *)NULL;
  2852. }
  2853. else
  2854. x = realAllocSpan (accumSpans);
  2855. if (x)
  2856. {
  2857. x->min = xmin;
  2858. x->max = xmax;
  2859. x->next = *f;
  2860. *f = x;
  2861. ++(accumSpans->nspans);
  2862. }
  2863. }
  2864. }
  2865. /* Reallocate the finalSpans array in an miAccumSpans structure to include
  2866. the specified value y. This is called only if y is outside the range
  2867. finalMiny..finalMaxy, which indexes the array. Returns the address, in
  2868. the finalSpans array, of the pointer to the head of the list of spans at
  2869. the new value of y. */
  2870. static struct finalSpan **
  2871. realFindSpan (miAccumSpans *accumSpans, int y)
  2872. {
  2873. struct finalSpan **newSpans, **t;
  2874. int newSize, newMiny, newMaxy;
  2875. int change;
  2876. int i, k;
  2877. if (y < accumSpans->finalMiny || y > accumSpans->finalMaxy)
  2878. /* need to expand... */
  2879. {
  2880. if (accumSpans->finalSize == 0)
  2881. {
  2882. accumSpans->finalMiny = y;
  2883. accumSpans->finalMaxy = y - 1;
  2884. }
  2885. if (y < accumSpans->finalMiny)
  2886. change = accumSpans->finalMiny - y;
  2887. else
  2888. change = y - accumSpans->finalMaxy;
  2889. /* ???!!! a ceiling on amount by which finalSpans is expanded !!!??? */
  2890. if (change >= SPAN_REALLOC)
  2891. change += SPAN_REALLOC;
  2892. else
  2893. change = SPAN_REALLOC;
  2894. newSize = accumSpans->finalSize + change;
  2895. newSpans =
  2896. (struct finalSpan **)mi_xmalloc (newSize * sizeof (struct finalSpan *));
  2897. newMiny = accumSpans->finalMiny;
  2898. newMaxy = accumSpans->finalMaxy;
  2899. if (y < accumSpans->finalMiny)
  2900. newMiny = accumSpans->finalMiny - change;
  2901. else
  2902. newMaxy = accumSpans->finalMaxy + change;
  2903. if (accumSpans->finalSpans)
  2904. {
  2905. memmove ((void *)(newSpans + (accumSpans->finalMiny - newMiny)),
  2906. (void *)(accumSpans->finalSpans),
  2907. accumSpans->finalSize * sizeof(struct finalSpan *));
  2908. free (accumSpans->finalSpans);
  2909. }
  2910. if ((i = accumSpans->finalMiny - newMiny) > 0)
  2911. for (k = 0, t = newSpans; k < i; k++, t++)
  2912. *t = (struct finalSpan *)NULL;
  2913. if ((i = newMaxy - accumSpans->finalMaxy) > 0)
  2914. for (k = 0, t = newSpans + newSize - i; k < i; k++, t++)
  2915. *t = (struct finalSpan *)NULL;
  2916. accumSpans->finalSpans = newSpans;
  2917. accumSpans->finalMaxy = newMaxy;
  2918. accumSpans->finalMiny = newMiny;
  2919. accumSpans->finalSize = newSize;
  2920. }
  2921. return &((accumSpans->finalSpans)[(y) - (accumSpans->finalMiny)]);
  2922. }
  2923. /* Return an unused span, by allocating a new chunk of spans and returning
  2924. the first span in the chunk. Called only if freeFinalSpans pointer in
  2925. the miAccumSpans structure is NULL, i.e., previously allocated chunk (if
  2926. any) is exhausted. The freeFinalSpans and chunks pointers are
  2927. updated. */
  2928. static struct finalSpan *
  2929. realAllocSpan (miAccumSpans *accumSpans)
  2930. {
  2931. struct finalSpanChunk *newChunk;
  2932. struct finalSpan *span;
  2933. int i;
  2934. /* allocate new chunk, add to head of chunk list */
  2935. newChunk = (struct finalSpanChunk *) mi_xmalloc (sizeof (struct finalSpanChunk));
  2936. newChunk->next = accumSpans->chunks;
  2937. accumSpans->chunks = newChunk;
  2938. /* point freeFinalSpans to the second span in the new chunk */
  2939. accumSpans->freeFinalSpans = newChunk->data + 1;
  2940. /* be sure `next' pointer of each span in the new chunk is NULL */
  2941. span = newChunk->data + 1;
  2942. for (i = 1; i < SPAN_CHUNK_SIZE - 1; i++)
  2943. {
  2944. span->next = span + 1;
  2945. span++;
  2946. }
  2947. span->next = (struct finalSpan *)NULL;
  2948. span = newChunk->data;
  2949. span->next = (struct finalSpan *)NULL;
  2950. return span;
  2951. }
  2952. /*** deallocation-related functions ***/
  2953. /* A public function for this module: paint spans that have been
  2954. accumulated in an miAccumSpans structure, in a specified pixel color;
  2955. also reset the structure, as if initAccumSpans() had been called.
  2956. Painting takes place to the specified miPaintedSet structure, by
  2957. invoking MI_PAINT_SPANS(). */
  2958. /* All painting done in this file goes through this function. */
  2959. static void
  2960. fillSpans (miPaintedSet *paintedSet, miPixel pixel, miAccumSpans *accumSpans)
  2961. {
  2962. struct finalSpan *span;
  2963. struct finalSpan **f;
  2964. int spany;
  2965. miPoint *ppt, *pptInit;
  2966. unsigned int *pwidth, *pwidthInit;
  2967. if (accumSpans->nspans == 0)
  2968. return;
  2969. /* from the miAccumSpans struct, construct an array of spans */
  2970. ppt = pptInit = (miPoint *) mi_xmalloc (accumSpans->nspans * sizeof (miPoint));
  2971. pwidth = pwidthInit = (unsigned int *) mi_xmalloc (accumSpans->nspans * sizeof (unsigned int));
  2972. for (spany = accumSpans->finalMiny, f = accumSpans->finalSpans;
  2973. spany <= accumSpans->finalMaxy;
  2974. spany++, f++)
  2975. {
  2976. for (span = *f; span; span = span->next)
  2977. {
  2978. if (span->max <= span->min)
  2979. continue;
  2980. ppt->x = span->min;
  2981. ppt->y = spany;
  2982. ++ppt;
  2983. *pwidth++ = (unsigned int)(span->max - span->min);
  2984. }
  2985. }
  2986. /* paint the spans to the miPaintedSet */
  2987. MI_PAINT_SPANS(paintedSet, pixel, ppt - pptInit, pptInit, pwidthInit)
  2988. /* free all spans in the miAccumSpans struct, reset it */
  2989. disposeFinalSpans (accumSpans);
  2990. accumSpans->finalMiny = 0;
  2991. accumSpans->finalMaxy = -1;
  2992. accumSpans->finalSize = 0;
  2993. accumSpans->nspans = 0;
  2994. }
  2995. static void
  2996. disposeFinalSpans (miAccumSpans *accumSpans)
  2997. {
  2998. struct finalSpanChunk *chunk, *next;
  2999. for (chunk = accumSpans->chunks; chunk; chunk = next)
  3000. {
  3001. next = chunk->next;
  3002. free (chunk);
  3003. }
  3004. accumSpans->chunks = (struct finalSpanChunk *)NULL;
  3005. accumSpans->freeFinalSpans = (struct finalSpan *)NULL;
  3006. free (accumSpans->finalSpans);
  3007. accumSpans->finalSpans = (struct finalSpan **)NULL;
  3008. }
  3009. /**********************************************************************/
  3010. /* A sub-module, used by drawArc(), that generates the spans associated
  3011. with an arc, and writes them to an in-core span accumulation by calling
  3012. newFinalSpan(). When this is used, computeAcc() and computeBounds()
  3013. have already been called, to compute `accelerators' (frequently used
  3014. quantities associated with the ellipse). hookX() and tailX() are called
  3015. to do additional geometry computations. */
  3016. /**********************************************************************/
  3017. /* forward references */
  3018. static void arcSpan (miAccumSpans *accumSpans, int y, int lx, int lw, int rx, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask);
  3019. static void arcSpan0 (miAccumSpans *accumSpans, int lx, int lw, int rx, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask);
  3020. static void tailSpan (miAccumSpans *accumSpans, int y, int lw, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask);
  3021. /* Generate the set of spans with the given y coordinate. */
  3022. static void
  3023. arcSpan (miAccumSpans *accumSpans, int y, int lx, int lw, int rx, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask)
  3024. {
  3025. int linx, loutx, rinx, routx;
  3026. double x, altx;
  3027. if (boundedLe (y, bounds->inneri))
  3028. {
  3029. linx = -(lx + lw);
  3030. rinx = rx;
  3031. }
  3032. else
  3033. {
  3034. /*
  3035. * intersection with left face
  3036. */
  3037. x = hookX (y + acc->fromIntY, def, bounds, acc, true);
  3038. if (acc->right.valid
  3039. && boundedLe (y + acc->fromIntY, bounds->right))
  3040. {
  3041. altx = intersectLine (y + acc->fromIntY, acc->right);
  3042. if (altx < x)
  3043. x = altx;
  3044. }
  3045. linx = -ICEIL(acc->fromIntX - x);
  3046. rinx = ICEIL(acc->fromIntX + x);
  3047. }
  3048. if (boundedLe (y, bounds->outeri))
  3049. {
  3050. loutx = -lx;
  3051. routx = rx + rw;
  3052. }
  3053. else
  3054. {
  3055. /*
  3056. * intersection with right face
  3057. */
  3058. x = hookX (y + acc->fromIntY, def, bounds, acc, false);
  3059. if (acc->left.valid
  3060. && boundedLe (y + acc->fromIntY, bounds->left))
  3061. {
  3062. altx = x;
  3063. x = intersectLine (y + acc->fromIntY, acc->left);
  3064. if (x < altx)
  3065. x = altx;
  3066. }
  3067. loutx = -ICEIL(acc->fromIntX - x);
  3068. routx = ICEIL(acc->fromIntX + x);
  3069. }
  3070. if (routx > rinx)
  3071. {
  3072. if (mask & 1)
  3073. newFinalSpan (accumSpans,
  3074. acc->yorgu - y,
  3075. acc->xorg + rinx, acc->xorg + routx);
  3076. if (mask & 8)
  3077. newFinalSpan (accumSpans,
  3078. acc->yorgl + y,
  3079. acc->xorg + rinx, acc->xorg + routx);
  3080. }
  3081. if (loutx > linx)
  3082. {
  3083. if (mask & 2)
  3084. newFinalSpan (accumSpans,
  3085. acc->yorgu - y,
  3086. acc->xorg - loutx, acc->xorg - linx);
  3087. if (mask & 4)
  3088. newFinalSpan (accumSpans,
  3089. acc->yorgl + y,
  3090. acc->xorg - loutx, acc->xorg - linx);
  3091. }
  3092. }
  3093. static void
  3094. arcSpan0 (miAccumSpans *accumSpans, int lx, int lw, int rx, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask)
  3095. {
  3096. double x;
  3097. if (boundedLe (0, bounds->inneri)
  3098. && acc->left.valid && boundedLe (0, bounds->left)
  3099. && acc->left.b > 0)
  3100. {
  3101. x = def->w - def->l;
  3102. if (acc->left.b < x)
  3103. x = acc->left.b;
  3104. lw = ICEIL(acc->fromIntX - x) - lx;
  3105. rw += rx;
  3106. rx = ICEIL(acc->fromIntX + x);
  3107. rw -= rx;
  3108. }
  3109. arcSpan (accumSpans, 0, lx, lw, rx, rw, def, bounds, acc, mask);
  3110. }
  3111. static void
  3112. tailSpan (miAccumSpans *accumSpans, int y, int lw, int rw, const struct arc_def *def, const struct arc_bound *bounds, const struct accelerators *acc, unsigned int mask)
  3113. {
  3114. double yy, xalt, x, lx, rx;
  3115. int n;
  3116. if (boundedLe(y, bounds->outeri))
  3117. arcSpan (accumSpans, y, 0, lw, -rw, rw, def, bounds, acc, mask);
  3118. else if (def->w != def->h)
  3119. {
  3120. yy = y + acc->fromIntY;
  3121. x = tailX(yy, def, bounds, acc);
  3122. if (yy == 0.0 && x == -rw - acc->fromIntX)
  3123. return;
  3124. if (acc->right.valid && boundedLe (yy, bounds->right))
  3125. {
  3126. rx = x;
  3127. lx = -x;
  3128. xalt = intersectLine (yy, acc->right);
  3129. if (xalt >= -rw - acc->fromIntX && xalt <= rx)
  3130. rx = xalt;
  3131. n = ICEIL(acc->fromIntX + lx);
  3132. if (lw > n)
  3133. {
  3134. if (mask & 2)
  3135. newFinalSpan (accumSpans,
  3136. acc->yorgu - y,
  3137. acc->xorg + n, acc->xorg + lw);
  3138. if (mask & 4)
  3139. newFinalSpan (accumSpans,
  3140. acc->yorgl + y,
  3141. acc->xorg + n, acc->xorg + lw);
  3142. }
  3143. n = ICEIL(acc->fromIntX + rx);
  3144. if (n > -rw)
  3145. {
  3146. if (mask & 1)
  3147. newFinalSpan (accumSpans,
  3148. acc->yorgu - y,
  3149. acc->xorg - rw, acc->xorg + n);
  3150. if (mask & 8)
  3151. newFinalSpan (accumSpans,
  3152. acc->yorgl + y,
  3153. acc->xorg - rw, acc->xorg + n);
  3154. }
  3155. }
  3156. arcSpan (accumSpans, y,
  3157. ICEIL(acc->fromIntX - x), 0,
  3158. ICEIL(acc->fromIntX + x), 0,
  3159. def, bounds, acc, mask);
  3160. }
  3161. }
  3162. /**********************************************************************/
  3163. /* The drawArc() function, which draws an arc to an in-core span
  3164. accumulation by invoking the functions in the previous sub-module. This
  3165. calls miComputeWideEllipse() to rasterize the ellipse of which the arc
  3166. is a part, and the helper functions computeAcc() and computeBounds().
  3167. It is the low-level `draw to memory' function invoked by miArcSegment().
  3168. drawZeroArc(), which follows, is simpler; it draws a degenerate
  3169. (horizontal or vertical) arc. */
  3170. /**********************************************************************/
  3171. /* forward references */
  3172. static void drawQuadrant (miAccumSpans *accumSpans, struct arc_def *def, struct accelerators *acc, int a0, int a1, unsigned int mask, miArcFace *right, miArcFace *left, miArcSpanData *spdata);
  3173. static void mirrorSppPoint (int quadrant, SppPoint *sppPoint);
  3174. /* Split an arc into pieces which are scan-converted in the first quadrant
  3175. * and mirrored into position. This is necessary as the scan-conversion
  3176. * code can only deal with arcs completely contained in the first quadrant.
  3177. */
  3178. /* ARGS: right,left save arc endpoints */
  3179. static void
  3180. drawArc (miAccumSpans *accumSpans, const miArc *tarc, unsigned int l, int a0, int a1, miArcFace *right, miArcFace *left, miEllipseCache *ellipseCache)
  3181. {
  3182. struct arc_def def;
  3183. struct accelerators acc;
  3184. int startq, endq, curq;
  3185. int rightq, leftq = 0, righta = 0, lefta = 0;
  3186. miArcFace *passRight, *passLeft;
  3187. int q0 = 0, q1 = 0;
  3188. unsigned int mask;
  3189. struct band
  3190. {
  3191. int a0, a1;
  3192. unsigned int mask;
  3193. } band[5], sweep[20];
  3194. int bandno, sweepno;
  3195. int i, j;
  3196. bool flipRight = false, flipLeft = false;
  3197. bool copyEnd = false;
  3198. miArcSpanData *spdata;
  3199. bool mustFree;
  3200. /* compute span data for the whole wide ellipse, also caching it for
  3201. speedy later retrieval */
  3202. spdata = miComputeWideEllipse (l, tarc, &mustFree, ellipseCache);
  3203. if (!spdata)
  3204. /* unknown failure, so punt */
  3205. return;
  3206. if (a1 < a0)
  3207. a1 += 360 * 64;
  3208. startq = a0 / (90 * 64);
  3209. if (a0 == a1)
  3210. endq = startq;
  3211. else
  3212. endq = (a1-1) / (90 * 64);
  3213. bandno = 0;
  3214. curq = startq;
  3215. rightq = -1;
  3216. for (;;)
  3217. {
  3218. switch (curq)
  3219. {
  3220. case 0:
  3221. if (a0 > 90 * 64)
  3222. q0 = 0;
  3223. else
  3224. q0 = a0;
  3225. if (a1 < 360 * 64)
  3226. q1 = IMIN (a1, 90 * 64);
  3227. else
  3228. q1 = 90 * 64;
  3229. if (curq == startq && a0 == q0 && rightq < 0)
  3230. {
  3231. righta = q0;
  3232. rightq = curq;
  3233. }
  3234. if (curq == endq && a1 == q1)
  3235. {
  3236. lefta = q1;
  3237. leftq = curq;
  3238. }
  3239. break;
  3240. case 1:
  3241. if (a1 < 90 * 64)
  3242. q0 = 0;
  3243. else
  3244. q0 = 180 * 64 - IMIN (a1, 180 * 64);
  3245. if (a0 > 180 * 64)
  3246. q1 = 90 * 64;
  3247. else
  3248. q1 = 180 * 64 - IMAX (a0, 90 * 64);
  3249. if (curq == startq && 180 * 64 - a0 == q1)
  3250. {
  3251. righta = q1;
  3252. rightq = curq;
  3253. }
  3254. if (curq == endq && 180 * 64 - a1 == q0)
  3255. {
  3256. lefta = q0;
  3257. leftq = curq;
  3258. }
  3259. break;
  3260. case 2:
  3261. if (a0 > 270 * 64)
  3262. q0 = 0;
  3263. else
  3264. q0 = IMAX (a0, 180 * 64) - 180 * 64;
  3265. if (a1 < 180 * 64)
  3266. q1 = 90 * 64;
  3267. else
  3268. q1 = IMIN (a1, 270 * 64) - 180 * 64;
  3269. if (curq == startq && a0 - 180*64 == q0)
  3270. {
  3271. righta = q0;
  3272. rightq = curq;
  3273. }
  3274. if (curq == endq && a1 - 180 * 64 == q1)
  3275. {
  3276. lefta = q1;
  3277. leftq = curq;
  3278. }
  3279. break;
  3280. case 3:
  3281. if (a1 < 270 * 64)
  3282. q0 = 0;
  3283. else
  3284. q0 = 360 * 64 - IMIN (a1, 360 * 64);
  3285. q1 = 360 * 64 - IMAX (a0, 270 * 64);
  3286. if (curq == startq && 360 * 64 - a0 == q1)
  3287. {
  3288. righta = q1;
  3289. rightq = curq;
  3290. }
  3291. if (curq == endq && 360 * 64 - a1 == q0)
  3292. {
  3293. lefta = q0;
  3294. leftq = curq;
  3295. }
  3296. break;
  3297. }
  3298. band[bandno].a0 = q0;
  3299. band[bandno].a1 = q1;
  3300. band[bandno].mask = 1 << curq;
  3301. bandno++;
  3302. if (curq == endq)
  3303. break;
  3304. curq++;
  3305. if (curq == 4)
  3306. {
  3307. a0 = 0;
  3308. a1 -= 360 * 64;
  3309. curq = 0;
  3310. endq -= 4;
  3311. }
  3312. }
  3313. sweepno = 0;
  3314. for (;;)
  3315. {
  3316. q0 = 90 * 64;
  3317. mask = 0;
  3318. /*
  3319. * find left-most point
  3320. */
  3321. for (i = 0; i < bandno; i++)
  3322. if (band[i].a0 <= q0)
  3323. {
  3324. q0 = band[i].a0;
  3325. q1 = band[i].a1;
  3326. mask = band[i].mask;
  3327. }
  3328. if (mask == 0)
  3329. break;
  3330. /*
  3331. * locate next point of change
  3332. */
  3333. for (i = 0; i < bandno; i++)
  3334. if (!(mask & band[i].mask))
  3335. {
  3336. if (band[i].a0 == q0)
  3337. {
  3338. if (band[i].a1 < q1)
  3339. q1 = band[i].a1;
  3340. mask |= band[i].mask;
  3341. }
  3342. else if (band[i].a0 < q1)
  3343. q1 = band[i].a0;
  3344. }
  3345. /*
  3346. * create a new sweep
  3347. */
  3348. sweep[sweepno].a0 = q0;
  3349. sweep[sweepno].a1 = q1;
  3350. sweep[sweepno].mask = mask;
  3351. sweepno++;
  3352. /*
  3353. * subtract the sweep from the affected bands
  3354. */
  3355. for (i = 0; i < bandno; i++)
  3356. if (band[i].a0 == q0)
  3357. {
  3358. band[i].a0 = q1;
  3359. /*
  3360. * check if this band is empty
  3361. */
  3362. if (band[i].a0 == band[i].a1)
  3363. band[i].a1 = band[i].a0 = 90 * 64 + 1;
  3364. }
  3365. }
  3366. computeAcc (tarc, l, &def, &acc);
  3367. for (j = 0; j < sweepno; j++)
  3368. {
  3369. mask = sweep[j].mask;
  3370. passRight = passLeft = (miArcFace *)NULL;
  3371. if (mask & (1 << rightq))
  3372. {
  3373. if (sweep[j].a0 == righta)
  3374. passRight = right;
  3375. else if (sweep[j].a1 == righta)
  3376. {
  3377. passLeft = right;
  3378. flipRight = true;
  3379. }
  3380. }
  3381. if (mask & (1 << leftq))
  3382. {
  3383. if (sweep[j].a1 == lefta)
  3384. {
  3385. if (passLeft)
  3386. copyEnd = true;
  3387. passLeft = left;
  3388. }
  3389. else if (sweep[j].a0 == lefta)
  3390. {
  3391. if (passRight)
  3392. copyEnd = true;
  3393. passRight = left;
  3394. flipLeft = true;
  3395. }
  3396. }
  3397. drawQuadrant (accumSpans, &def, &acc, sweep[j].a0, sweep[j].a1, mask,
  3398. passRight, passLeft, spdata);
  3399. }
  3400. /* when copyEnd is true, both ends of the arc were computed at the same
  3401. * time; drawQuadrant only takes one end though, so the left end will be
  3402. * the only one holding the data. Copy it from there.
  3403. */
  3404. if (copyEnd)
  3405. *right = *left;
  3406. /*
  3407. * mirror the coordinates generated for the
  3408. * faces of the arc
  3409. */
  3410. if (right)
  3411. {
  3412. mirrorSppPoint (rightq, &right->clock);
  3413. mirrorSppPoint (rightq, &right->center);
  3414. mirrorSppPoint (rightq, &right->counterClock);
  3415. if (flipRight)
  3416. {
  3417. SppPoint temp;
  3418. temp = right->clock;
  3419. right->clock = right->counterClock;
  3420. right->counterClock = temp;
  3421. }
  3422. }
  3423. if (left)
  3424. {
  3425. mirrorSppPoint (leftq, &left->counterClock);
  3426. mirrorSppPoint (leftq, &left->center);
  3427. mirrorSppPoint (leftq, &left->clock);
  3428. if (flipLeft)
  3429. {
  3430. SppPoint temp;
  3431. temp = left->clock;
  3432. left->clock = left->counterClock;
  3433. left->counterClock = temp;
  3434. }
  3435. }
  3436. if (mustFree)
  3437. {
  3438. free (spdata->spans);
  3439. free (spdata);
  3440. }
  3441. }
  3442. /* ARGS: spdata = rasterized wide ellipse */
  3443. static void
  3444. drawQuadrant (miAccumSpans *accumSpans, struct arc_def *def, struct accelerators *acc, int a0, int a1, unsigned int mask, miArcFace *right, miArcFace *left, miArcSpanData *spdata)
  3445. {
  3446. struct arc_bound bound;
  3447. double yy, x, xalt;
  3448. int y, miny, maxy;
  3449. int n;
  3450. miArcSpan *span;
  3451. def->a0 = ((double) a0) / 64.0;
  3452. def->a1 = ((double) a1) / 64.0;
  3453. computeBound (def, &bound, acc, right, left);
  3454. yy = bound.inner.min;
  3455. if (bound.outer.min < yy)
  3456. yy = bound.outer.min;
  3457. miny = ICEIL(yy - acc->fromIntY);
  3458. yy = bound.inner.max;
  3459. if (bound.outer.max > yy)
  3460. yy = bound.outer.max;
  3461. maxy = (int)floor(yy - acc->fromIntY);
  3462. y = spdata->k;
  3463. span = spdata->spans;
  3464. if (spdata->top)
  3465. /* rasterized ellipse contains a `top point' */
  3466. {
  3467. if (a1 == 90 * 64 && (mask & 1))
  3468. newFinalSpan (accumSpans,
  3469. acc->yorgu - y - 1, acc->xorg, acc->xorg + 1);
  3470. span++;
  3471. }
  3472. /* loop through one-span ArcSpans, at successive values of y */
  3473. for (n = spdata->count1; --n >= 0; )
  3474. {
  3475. if (y < miny)
  3476. return;
  3477. if (y <= maxy)
  3478. {
  3479. /* generate spans at this y value */
  3480. arcSpan (accumSpans, y,
  3481. span->lx, -span->lx, 0, span->lx + span->lw,
  3482. def, &bound, acc, mask);
  3483. if (span->rw + span->rx)
  3484. tailSpan (accumSpans, y, -span->rw, -span->rx, def, &bound, acc, mask);
  3485. }
  3486. y--;
  3487. span++;
  3488. }
  3489. if (y < miny)
  3490. return;
  3491. if (spdata->hole)
  3492. /* have a one-pixel hole to fill in */
  3493. {
  3494. if (y <= maxy)
  3495. /* generate a one-point span at this y value */
  3496. arcSpan (accumSpans, y, 0, 0, 0, 1,
  3497. def, &bound, acc, mask & 0xc);
  3498. }
  3499. /* loop through two-span ArcSpans, at successive values of y */
  3500. for (n = spdata->count2; --n >= 0; )
  3501. {
  3502. if (y < miny)
  3503. return;
  3504. if (y <= maxy)
  3505. /* generate the two spans at this y value */
  3506. arcSpan (accumSpans, y, span->lx, span->lw, span->rx, span->rw,
  3507. def, &bound, acc, mask);
  3508. y--;
  3509. span++;
  3510. }
  3511. if (spdata->bot && miny <= y && y <= maxy)
  3512. /* have a `horizontal centerline' ArcSpan; treat it specially */
  3513. {
  3514. unsigned int m = mask;
  3515. if (y == miny)
  3516. m &= 0xc;
  3517. if (span->rw <= 0)
  3518. {
  3519. arcSpan0 (accumSpans, span->lx, -span->lx, 0, span->lx + span->lw,
  3520. def, &bound, acc, m);
  3521. if (span->rw + span->rx)
  3522. tailSpan (accumSpans, y, -span->rw, -span->rx, def, &bound, acc, m);
  3523. }
  3524. else
  3525. arcSpan0 (accumSpans, span->lx, span->lw, span->rx, span->rw,
  3526. def, &bound, acc, m);
  3527. y--;
  3528. }
  3529. while (y >= miny)
  3530. {
  3531. yy = y + acc->fromIntY;
  3532. if (def->w == def->h)
  3533. {
  3534. xalt = def->w - def->l;
  3535. x = -sqrt(xalt * xalt - yy * yy);
  3536. }
  3537. else
  3538. {
  3539. x = tailX(yy, def, &bound, acc);
  3540. if (acc->left.valid && boundedLe (yy, bound.left))
  3541. {
  3542. xalt = intersectLine (yy, acc->left);
  3543. if (xalt < x)
  3544. x = xalt;
  3545. }
  3546. if (acc->right.valid && boundedLe (yy, bound.right))
  3547. {
  3548. xalt = intersectLine (yy, acc->right);
  3549. if (xalt < x)
  3550. x = xalt;
  3551. }
  3552. }
  3553. /* generate span at this y value */
  3554. arcSpan (accumSpans, y,
  3555. ICEIL(acc->fromIntX - x), 0,
  3556. ICEIL(acc->fromIntX + x), 0,
  3557. def, &bound, acc, mask);
  3558. y--;
  3559. }
  3560. }
  3561. static void
  3562. mirrorSppPoint (int quadrant, SppPoint *sppPoint)
  3563. {
  3564. switch (quadrant)
  3565. {
  3566. case 0:
  3567. break;
  3568. case 1:
  3569. sppPoint->x = -sppPoint->x;
  3570. break;
  3571. case 2:
  3572. sppPoint->x = -sppPoint->x;
  3573. sppPoint->y = -sppPoint->y;
  3574. break;
  3575. case 3:
  3576. sppPoint->y = -sppPoint->y;
  3577. break;
  3578. }
  3579. /*
  3580. * and translate to X coordinate system
  3581. */
  3582. sppPoint->y = -sppPoint->y;
  3583. }
  3584. /***********************************************************************/
  3585. /* Draw a degenerate (zero width/height) arc. Left and right faces are
  3586. * computed. Called by miArcSegment() to handle the degenerate case:
  3587. * tarc->width = 0 or tarc->height = 0. */
  3588. /***********************************************************************/
  3589. /* ARGS: left,right save arc endpoints */
  3590. static void
  3591. drawZeroArc (miAccumSpans *accumSpans, const miArc *tarc, unsigned int lw, miArcFace *left, miArcFace *right)
  3592. {
  3593. double x0 = 0.0, y0 = 0.0, x1 = 0.0, y1 = 0.0;
  3594. double w, h, x, y;
  3595. double xmax, ymax, xmin, ymin;
  3596. int a0, a1;
  3597. double a, startAngle, endAngle;
  3598. double l, lx, ly;
  3599. l = 0.5 * lw;
  3600. a0 = tarc->angle1;
  3601. a1 = tarc->angle2;
  3602. if (a1 > FULLCIRCLE)
  3603. a1 = FULLCIRCLE;
  3604. else if (a1 < -FULLCIRCLE)
  3605. a1 = -FULLCIRCLE;
  3606. w = 0.5 * tarc->width;
  3607. h = 0.5 * tarc->height;
  3608. /*
  3609. * play in X coordinates right away
  3610. */
  3611. startAngle = - ((double) a0 / 64.0);
  3612. endAngle = - ((double) (a0 + a1) / 64.0);
  3613. xmax = -w;
  3614. xmin = w;
  3615. ymax = -h;
  3616. ymin = h;
  3617. a = startAngle;
  3618. for (;;)
  3619. {
  3620. x = w * miDcos(a);
  3621. y = h * miDsin(a);
  3622. if (a == startAngle)
  3623. {
  3624. x0 = x;
  3625. y0 = y;
  3626. }
  3627. if (a == endAngle)
  3628. {
  3629. x1 = x;
  3630. y1 = y;
  3631. }
  3632. if (x > xmax)
  3633. xmax = x;
  3634. if (x < xmin)
  3635. xmin = x;
  3636. if (y > ymax)
  3637. ymax = y;
  3638. if (y < ymin)
  3639. ymin = y;
  3640. if (a == endAngle)
  3641. break;
  3642. if (a1 < 0) /* clockwise */
  3643. {
  3644. if (floor (a / 90.0) == floor (endAngle / 90.0))
  3645. a = endAngle;
  3646. else
  3647. a = 90 * (floor (a/90.0) + 1);
  3648. }
  3649. else
  3650. {
  3651. if (ceil (a / 90.0) == ceil (endAngle / 90.0))
  3652. a = endAngle;
  3653. else
  3654. a = 90 * (ceil (a/90.0) - 1);
  3655. }
  3656. }
  3657. lx = ly = l;
  3658. if ((x1 - x0) + (y1 - y0) < 0)
  3659. lx = ly = -l;
  3660. if (h)
  3661. ly = 0.0;
  3662. else
  3663. lx = 0.0;
  3664. if (right)
  3665. {
  3666. right->center.x = x0;
  3667. right->center.y = y0;
  3668. right->clock.x = x0 - lx;
  3669. right->clock.y = y0 - ly;
  3670. right->counterClock.x = x0 + lx;
  3671. right->counterClock.y = y0 + ly;
  3672. }
  3673. if (left)
  3674. {
  3675. left->center.x = x1;
  3676. left->center.y = y1;
  3677. left->clock.x = x1 + lx;
  3678. left->clock.y = y1 + ly;
  3679. left->counterClock.x = x1 - lx;
  3680. left->counterClock.y = y1 - ly;
  3681. }
  3682. x0 = xmin;
  3683. x1 = xmax;
  3684. y0 = ymin;
  3685. y1 = ymax;
  3686. if (ymin != y1)
  3687. {
  3688. xmin = -l;
  3689. xmax = l;
  3690. }
  3691. else
  3692. {
  3693. ymin = -l;
  3694. ymax = l;
  3695. }
  3696. if (xmax != xmin && ymax != ymin)
  3697. /* construct a rectangle and `paint' it */
  3698. {
  3699. int minx, maxx, miny, maxy;
  3700. int xorg, yorg, width, height;
  3701. minx = ICEIL(xmin + w) + tarc->x;
  3702. maxx = ICEIL(xmax + w) + tarc->x;
  3703. miny = ICEIL(ymin + h) + tarc->y;
  3704. maxy = ICEIL(ymax + h) + tarc->y;
  3705. xorg = minx;
  3706. yorg = miny;
  3707. width = maxx - minx;
  3708. height = maxy - miny;
  3709. /* paint rectangle to the in-core miAccumSpans struct, except for its
  3710. right and bottom edges */
  3711. while (height--)
  3712. newFinalSpan (accumSpans, yorg, xorg, xorg + width);
  3713. }
  3714. }