diff --git a/.gitattributes b/.gitattributes index 384c8eef94e..8ec8d89f1a0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1247,6 +1247,12 @@ Qt_widget/doc_tex/Qt_widget/triangulation.gif -text svneol=unset#unset Qt_widget/doc_tex/Qt_widget/triangulation.pdf -text svneol=unset#unset Qt_widget/src/CGALQt/CGALQt.sln -text Qt_widget/src/CGALQt/CGALQt.vcproj -text +Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges.eps -text +Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges.pdf -text +Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.eps -text +Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.jpg -text +Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.pdf -text +Ridges_3/include/CGAL/algo.C -text Robustness/demo/Robustness/robustness.vcproj -text SearchStructures/doc_tex/SearchStructures/d-range.eps -text SearchStructures/doc_tex/SearchStructures/d-range.gif -text svneol=unset#unset diff --git a/Ridges_3/doc_tex/Ridges_3/Ridges_3_user.tex b/Ridges_3/doc_tex/Ridges_3/Ridges_3_user.tex new file mode 100644 index 00000000000..38e439aba00 --- /dev/null +++ b/Ridges_3/doc_tex/Ridges_3/Ridges_3_user.tex @@ -0,0 +1,158 @@ +This chapter describes the \cgal's package for the extraction of +ridges on meshes. Given a smooth surface, a ridge is a curve along +which one of the principal curvatures has an extremum along its +curvature line. Ridges are curves of {\em extremal} curvature and +therefore encode important informations used in segmentation, +registration, matching and surface analysis. Based on the results of +the article \cite{rr}, we propose several algorithms to identify and +extract different parts of this singular ridge curve and some of its +singularites on a surface given as a mesh. + + +\subsection{Overview} +%%%%%%%%%%%%%%%%%%%%%% + +2 main versions + +\begin{itemize} +\item +non-topologically oriented: we output several lists of ridges which +are polylines, each list associated to a type: crest min/max, +ellip/hyper, red/blue. + +each line has a weight enabling interactive filtering for the visu + +\item +topologically oriented : we output a list of umbilics and some lists +of ridges outside umbilic patches, turning points? +\end{itemize} + + +%%%%%%%%%%%%%%%%%%%%%%% +\section{Introduction} +\label{sec:intro} +%%%%%%%%%%%%%%%%%%%%%%% + +\subsection{Ridges of a smooth surface} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +A comprehensive description of ridges can be found in +\cite{ip-nss-71,hgyg-ttdpf-99,ip-gd-01}, and in the sequel, we just +introduce the basic notions so as to explain our algorithms. +Consider a smooth embedded surface, and denote $k_1$ and $k_2$ the +principal curvatures, with $k_1\geq k_2$. Umbilics are the points +where $k_1=k_2$. For any non umbilical point, the corresponding +principal directions of curvature are well defined, and we denote them +$d_1$ and $d_2$. In local coordinates, we denote $\langle , \rangle$ +the inner product induced by the ambient Euclidean space, and $dk_1$, +$dk_2$ the gradients of the principal curvatures. Ridges, illustrated +on Figs \ref{pict:ellipsoid_ridges} and \ref{fig:ridges_ellipsoid}, +are defined by: +%% +\begin{definition} +\label{def:ridge-extrema} +A non umbilical point is called +\begin{itemize} +\item +%a blue ridge point if $\langle dk_1,d_1 \rangle=0$, +a blue ridge point if the {\em extremality coefficient} $b_0=\langle +dk_1,d_1 \rangle$ vanishes, i.e. $b_0=0$. + +\item +%a red ridge point if $\langle dk_2,d_2 \rangle=0$. +a red ridge point if the {\em extremality coefficient} $b_3=\langle +dk_2,d_2 \rangle$ vanishes, i.e. $b_3=0$. + +\end{itemize} +\end{definition} +%We denote $b_0=\langle dk_1,d_1 \rangle$ and $b_3=\langle dk_2,d_2 +%\rangle$, and we call these functions the {\em extremality +%coefficients}. +%% +Notice that, as the principal curvatures are not differentiable at +umbilics, the extremality coefficients are not defined at such +points. In addition, the sign of the extremality coefficients is not +defined since the principal directions can be oriented by two opposite +unit vectors. Apart from umbilics, special points on ridges are {\em +purple} points, which correspond to intersections between red and a +blue ridges. The previous characterization of ridges involves +third-order differential properties. Using fourth-order differential +quantities, a ridge point can further be qualified as {\em elliptic} +if it corresponds to a maximum of $k_1$ or a minimum of $k_2$, or {\em +hyperbolic} otherwise. Ridges of a given color change from elliptic to +hyperbolic at special points called {\em turning} points. + +The calculation of ridges poses difficult problems, which are of three +kinds. + +\paragraph{Topological difficulties.} +Ridges of a smooth surface form a singular curve on the surface, with +self-intersections at umbilics (more precisely at so-called 3-ridges +umbilics), and purple points. Moreover, ridges have complex +interactions with curvature lines at turning points. From the +application standpoint, reporting ridges of a surface faithfully +requires reporting umbilics, purple points and turning points. + +\paragraph{Numerical difficulties.} +As pointed out above, ridges are characterized and qualified through +third and fourth order derivatives of the surface. Estimating them +depends on the particular type of surface processed ---implicitly +defined, parameterized, discretized by a mesh--- and is numerically a +difficult task. + +\paragraph{Orientation difficulties.} +Since coefficients $b_0$ and $b_3$ depend on a given orientation of +the principal directions, their sign is not well defined. +Practically, tracking the sign change of functions whose sign depends +on the particular orientation of the frame in which they are expressed +poses a problem. In particular, tracking a zero-crossing of $b_0$ or +$b_3$ from sign changes along a curve segment on the surface imposes +to find a coherent orientation of the principal frame at the +endpoints. Given two principal directions at these endpoints, one way +to find a local orientation consists of choosing two vectors so that +they make an acute angle, whence the name {\em Acute Rule}. +%% + +\begin{minipage}[c]{.45\linewidth} +\begin{figure}[H] +\centerline{ +\includegraphics[height=5cm]{Ridges_3/ellipsoid_ridges_mesh}} +\caption{Umbilics, ridges, and principal blue foliation on the +ellipsoid (10k points)} +\label{pict:ellipsoid_ridges} +\end{figure} +\end{minipage} +%% +\hfill +%% +\begin{minipage}[c]{.45\linewidth} +\begin{figure}[H] +\centerline{ +\includegraphics[height=5cm]{Ridges_3/ellipsoid_ridges}} +\caption{Schematic view of the umbilics and the ridges. Max of $k_1$: +blue; Min of $k_1$: green; Min of $k_2$: red; Max of $k_2$: yellow} +\label{fig:ridges_ellipsoid} +\end{figure} +\end{minipage} + + + +%%%%%%%%%%%%%%%%%%%%%%% +\section{Software Design} +%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Options and interface specifications} +%%%%%%%%%%%%%%%%%%%%% + +\subsection{Template parameters} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\subsection{Output} +%%%%%%%%%%%%%%%%%%%% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\section{Examples} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges.eps b/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges.eps new file mode 100644 index 00000000000..4af13852994 --- /dev/null +++ b/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges.eps @@ -0,0 +1,592 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Creator: dvips(k) 5.94a Copyright 2003 Radical Eye Software +%%Title: 28549.dvi +%%BoundingBox: 80 530 339 721 +%%EndComments +%DVIPSWebPage: (www.radicaleye.com) +%DVIPSCommandLine: dvips -E -o ridges_ellipsoid.eps 28549.dvi +%DVIPSParameters: dpi=600 +%DVIPSSource: TeX output 2004.09.02:1750 +%%BeginProcSet: tex.pro 0 0 +%! +/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S +N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72 +mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0 +0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{ +landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize +mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[ +matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round +exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{ +statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0] +N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin +/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array +/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2 +array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N +df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A +definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get +}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub} +B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr +1 add N}if}B/CharBuilder{save 3 1 roll S A/base get 2 index get S +/BitMaps get S get/Cd X pop/ctr 0 N Cdx 0 Cx Cy Ch sub Cx Cw add Cy +setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx sub Cy .1 sub]{Ci}imagemask +restore}B/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn +/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put +}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{ +bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A +mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{ +SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{ +userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X +1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4 +index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N +/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{ +/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT) +(LaserWriter 16/600)]{A length product length le{A length product exch 0 +exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse +end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask +grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot} +imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round +exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto +fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p +delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M} +B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{ +p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S +rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end + +%%EndProcSet +%%BeginProcSet: special.pro 0 0 +%! +TeXDict begin/SDict 200 dict N SDict begin/@SpecialDefaults{/hs 612 N +/vs 792 N/ho 0 N/vo 0 N/hsc 1 N/vsc 1 N/ang 0 N/CLIP 0 N/rwiSeen false N +/rhiSeen false N/letter{}N/note{}N/a4{}N/legal{}N}B/@scaleunit 100 N +/@hscale{@scaleunit div/hsc X}B/@vscale{@scaleunit div/vsc X}B/@hsize{ +/hs X/CLIP 1 N}B/@vsize{/vs X/CLIP 1 N}B/@clip{/CLIP 2 N}B/@hoffset{/ho +X}B/@voffset{/vo X}B/@angle{/ang X}B/@rwi{10 div/rwi X/rwiSeen true N}B +/@rhi{10 div/rhi X/rhiSeen true N}B/@llx{/llx X}B/@lly{/lly X}B/@urx{ +/urx X}B/@ury{/ury X}B/magscale true def end/@MacSetUp{userdict/md known +{userdict/md get type/dicttype eq{userdict begin md length 10 add md +maxlength ge{/md md dup length 20 add dict copy def}if end md begin +/letter{}N/note{}N/legal{}N/od{txpose 1 0 mtx defaultmatrix dtransform S +atan/pa X newpath clippath mark{transform{itransform moveto}}{transform{ +itransform lineto}}{6 -2 roll transform 6 -2 roll transform 6 -2 roll +transform{itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll +curveto}}{{closepath}}pathforall newpath counttomark array astore/gc xdf +pop ct 39 0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack} +if}N/txpose{pxs pys scale ppr aload pop por{noflips{pop S neg S TR pop 1 +-1 scale}if xflip yflip and{pop S neg S TR 180 rotate 1 -1 scale ppr 3 +get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip +yflip not and{pop S neg S TR pop 180 rotate ppr 3 get ppr 1 get neg sub +neg 0 TR}if yflip xflip not and{ppr 1 get neg ppr 0 get neg TR}if}{ +noflips{TR pop pop 270 rotate 1 -1 scale}if xflip yflip and{TR pop pop +90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get +neg sub neg TR}if xflip yflip not and{TR pop pop 90 rotate ppr 3 get ppr +1 get neg sub neg 0 TR}if yflip xflip not and{TR pop pop 270 rotate ppr +2 get ppr 0 get neg sub neg 0 S TR}if}ifelse scaleby96{ppr aload pop 4 +-1 roll add 2 div 3 1 roll add 2 div 2 copy TR .96 dup scale neg S neg S +TR}if}N/cp{pop pop showpage pm restore}N end}if}if}N/normalscale{ +Resolution 72 div VResolution 72 div neg scale magscale{DVImag dup scale +}if 0 setgray}N/psfts{S 65781.76 div N}N/startTexFig{/psf$SavedState +save N userdict maxlength dict begin/magscale true def normalscale +currentpoint TR/psf$ury psfts/psf$urx psfts/psf$lly psfts/psf$llx psfts +/psf$y psfts/psf$x psfts currentpoint/psf$cy X/psf$cx X/psf$sx psf$x +psf$urx psf$llx sub div N/psf$sy psf$y psf$ury psf$lly sub div N psf$sx +psf$sy scale psf$cx psf$sx div psf$llx sub psf$cy psf$sy div psf$ury sub +TR/showpage{}N/erasepage{}N/copypage{}N/p 3 def @MacSetUp}N/doclip{ +psf$llx psf$lly psf$urx psf$ury currentpoint 6 2 roll newpath 4 copy 4 2 +roll moveto 6 -1 roll S lineto S lineto S lineto closepath clip newpath +moveto}N/endTexFig{end psf$SavedState restore}N/@beginspecial{SDict +begin/SpecialSave save N gsave normalscale currentpoint TR +@SpecialDefaults count/ocount X/dcount countdictstack N}N/@setspecial{ +CLIP 1 eq{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto +closepath clip}if ho vo TR hsc vsc scale ang rotate rwiSeen{rwi urx llx +sub div rhiSeen{rhi ury lly sub div}{dup}ifelse scale llx neg lly neg TR +}{rhiSeen{rhi ury lly sub div dup scale llx neg lly neg TR}if}ifelse +CLIP 2 eq{newpath llx lly moveto urx lly lineto urx ury lineto llx ury +lineto closepath clip}if/showpage{}N/erasepage{}N/copypage{}N newpath}N +/@endspecial{count ocount sub{pop}repeat countdictstack dcount sub{end} +repeat grestore SpecialSave restore end}N/@defspecial{SDict begin}N +/@fedspecial{end}B/li{lineto}B/rl{rlineto}B/rc{rcurveto}B/np{/SaveX +currentpoint/SaveY X N 1 setlinecap newpath}N/st{stroke SaveX SaveY +moveto}N/fil{fill SaveX SaveY moveto}N/ellipse{/endangle X/startangle X +/yrad X/xrad X/savematrix matrix currentmatrix N TR xrad yrad scale 0 0 +1 startangle endangle arc savematrix setmatrix}N end + +%%EndProcSet +%%BeginProcSet: color.pro 0 0 +%! +TeXDict begin/setcmykcolor where{pop}{/setcmykcolor{dup 10 eq{pop +setrgbcolor}{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll +}repeat setrgbcolor pop}ifelse}B}ifelse/TeXcolorcmyk{setcmykcolor}def +/TeXcolorrgb{setrgbcolor}def/TeXcolorgrey{setgray}def/TeXcolorgray{ +setgray}def/TeXcolorhsb{sethsbcolor}def/currentcmykcolor where{pop}{ +/currentcmykcolor{currentrgbcolor 10}B}ifelse/DC{exch dup userdict exch +known{pop pop}{X}ifelse}B/GreenYellow{0.15 0 0.69 0 setcmykcolor}DC +/Yellow{0 0 1 0 setcmykcolor}DC/Goldenrod{0 0.10 0.84 0 setcmykcolor}DC +/Dandelion{0 0.29 0.84 0 setcmykcolor}DC/Apricot{0 0.32 0.52 0 +setcmykcolor}DC/Peach{0 0.50 0.70 0 setcmykcolor}DC/Melon{0 0.46 0.50 0 +setcmykcolor}DC/YellowOrange{0 0.42 1 0 setcmykcolor}DC/Orange{0 0.61 +0.87 0 setcmykcolor}DC/BurntOrange{0 0.51 1 0 setcmykcolor}DC +/Bittersweet{0 0.75 1 0.24 setcmykcolor}DC/RedOrange{0 0.77 0.87 0 +setcmykcolor}DC/Mahogany{0 0.85 0.87 0.35 setcmykcolor}DC/Maroon{0 0.87 +0.68 0.32 setcmykcolor}DC/BrickRed{0 0.89 0.94 0.28 setcmykcolor}DC/Red{ +0 1 1 0 setcmykcolor}DC/OrangeRed{0 1 0.50 0 setcmykcolor}DC/RubineRed{ +0 1 0.13 0 setcmykcolor}DC/WildStrawberry{0 0.96 0.39 0 setcmykcolor}DC +/Salmon{0 0.53 0.38 0 setcmykcolor}DC/CarnationPink{0 0.63 0 0 +setcmykcolor}DC/Magenta{0 1 0 0 setcmykcolor}DC/VioletRed{0 0.81 0 0 +setcmykcolor}DC/Rhodamine{0 0.82 0 0 setcmykcolor}DC/Mulberry{0.34 0.90 +0 0.02 setcmykcolor}DC/RedViolet{0.07 0.90 0 0.34 setcmykcolor}DC +/Fuchsia{0.47 0.91 0 0.08 setcmykcolor}DC/Lavender{0 0.48 0 0 +setcmykcolor}DC/Thistle{0.12 0.59 0 0 setcmykcolor}DC/Orchid{0.32 0.64 0 +0 setcmykcolor}DC/DarkOrchid{0.40 0.80 0.20 0 setcmykcolor}DC/Purple{ +0.45 0.86 0 0 setcmykcolor}DC/Plum{0.50 1 0 0 setcmykcolor}DC/Violet{ +0.79 0.88 0 0 setcmykcolor}DC/RoyalPurple{0.75 0.90 0 0 setcmykcolor}DC +/BlueViolet{0.86 0.91 0 0.04 setcmykcolor}DC/Periwinkle{0.57 0.55 0 0 +setcmykcolor}DC/CadetBlue{0.62 0.57 0.23 0 setcmykcolor}DC +/CornflowerBlue{0.65 0.13 0 0 setcmykcolor}DC/MidnightBlue{0.98 0.13 0 +0.43 setcmykcolor}DC/NavyBlue{0.94 0.54 0 0 setcmykcolor}DC/RoyalBlue{1 +0.50 0 0 setcmykcolor}DC/Blue{1 1 0 0 setcmykcolor}DC/Cerulean{0.94 0.11 +0 0 setcmykcolor}DC/Cyan{1 0 0 0 setcmykcolor}DC/ProcessBlue{0.96 0 0 0 +setcmykcolor}DC/SkyBlue{0.62 0 0.12 0 setcmykcolor}DC/Turquoise{0.85 0 +0.20 0 setcmykcolor}DC/TealBlue{0.86 0 0.34 0.02 setcmykcolor}DC +/Aquamarine{0.82 0 0.30 0 setcmykcolor}DC/BlueGreen{0.85 0 0.33 0 +setcmykcolor}DC/Emerald{1 0 0.50 0 setcmykcolor}DC/JungleGreen{0.99 0 +0.52 0 setcmykcolor}DC/SeaGreen{0.69 0 0.50 0 setcmykcolor}DC/Green{1 0 +1 0 setcmykcolor}DC/ForestGreen{0.91 0 0.88 0.12 setcmykcolor}DC +/PineGreen{0.92 0 0.59 0.25 setcmykcolor}DC/LimeGreen{0.50 0 1 0 +setcmykcolor}DC/YellowGreen{0.44 0 0.74 0 setcmykcolor}DC/SpringGreen{ +0.26 0 0.76 0 setcmykcolor}DC/OliveGreen{0.64 0 0.95 0.40 setcmykcolor} +DC/RawSienna{0 0.72 1 0.45 setcmykcolor}DC/Sepia{0 0.83 1 0.70 +setcmykcolor}DC/Brown{0 0.81 1 0.60 setcmykcolor}DC/Tan{0.14 0.42 0.56 0 +setcmykcolor}DC/Gray{0 0 0 0.50 setcmykcolor}DC/Black{0 0 0 1 +setcmykcolor}DC/White{0 0 0 0 setcmykcolor}DC end + +%%EndProcSet +TeXDict begin 40258437 52099154 1000 600 600 (28549.dvi) +@start end +%%EndProlog +%%BeginSetup +%%Feature: *Resolution 600dpi +TeXDict begin + end +%%EndSetup +TeXDict begin 1 0 bop White 0 3 2215 4 v 0 1474 4 1471 +v Black -1407 4072 a @beginspecial 100 @hscale 100 @vscale +@setspecial +%%BeginDocument: ridges_ellipsoid.ipe +%!PS-Adobe-2.0 EPSF-1.2 +%%Creator: Ipe 5.0 +%%BoundingBox: 171 313 428 486 +%%EndComments +{\catcode37=9\def\IPEdummy{({{)}} pop +%%}\makeatletter\let\@notdefinable\relax +%%\def\IPEc#1[#2]#3{\newcommand{#1}[#2]{#3}\ignorespaces}\@ifundefined +%%{selectfont}{\let\selectfont\relax\def\fontsize#1#2{}}{}\makeatother +%%\IPEc\IPEput[4]{\put(0,0){\special{psfile=\IPEfile}}} +%%\IPEc\IPEmp[2]{\minipage[t]{#1bp}#2\special{color pop}\endminipage} +%%\IPEc\IPEtext[1]{\makebox(0,0)[lb]{#1\special{color pop}}} +%%\IPEc\IPEfs[1]{\IPEcolfs{0 0 0}{#1}} +%%\IPEc\IPEcolfs[2]{\dimen0=#2pt\fontsize{#2}{1.2\dimen0}\selectfont +%%\special{color push rgb #1}} +%%\IPEc\IPEsize[2]{\unitlength1bp\ignorespaces} +%%\IPEsize{255.607}{170.52} +%%\begin{picture}(255.607,170.52)(172.196,314.74) +%%\IPEput{171}{313}{428}{486} +%%\end{picture}\endinput} +%% Ipe postscript prologue + +/IpeDict 60 dict def +IpeDict begin +/origmatrix matrix currentmatrix def + +/sg {setgray} bind def +/sc {setrgbcolor} bind def +/ss {0 setdash setlinewidth} bind def +/sk {stroke} bind def +/fi {fill} bind def +/sfi {gsave fill grestore} bind def +/mt {moveto} bind def +/lt {lineto} bind def +/np {newpath} bind def +/cl {closepath} bind def +/N {moveto} bind def +/L {lineto} bind def +/E {lineto} bind def +/C {lineto closepath} bind def +%%%% +%% x y size dx dy -> ar -> x y [ draws arrowhead, computes new vertex ] +/smallarrow {gsave exch atan 4 2 roll translate rotate dup scale +newpath 0 0 moveto -1 0.3 lineto -1 -0.3 lineto closepath fill +-1 0 moveto currentpoint transform grestore itransform} bind def +/ar {gsave exch atan 4 2 roll translate rotate dup scale +newpath 0 0 moveto -1 0.3 lineto -1 -0.3 lineto closepath +gsave origmatrix setmatrix [] 0 setdash stroke grestore fill +0 0 moveto currentpoint transform grestore itransform} bind def +%%%% +/af {ar moveto} bind def +/at {ar lineto} bind def +%% x y size dx dy -> arw -> [ draws arrowhead ] +/arw {ar pop pop} bind def +%%%% +/ci {0 360 arc} bind def +/el {gsave concat 0 exch 0 exch 0 360 newpath arc origmatrix +setmatrix} bind def +/gs {gsave} bind def +/gr {grestore} bind def +/gsts {gsave translate scale } bind def +%% +/marker {gsave translate 0 setlinewidth [] 0 setdash newpath} bind def +/m1 {marker 0 exch 0 exch 0 360 arc stroke grestore} bind def +/m2 {marker 0 exch 0 exch 0 360 arc fill grestore} bind def +/m3 {marker dup dup moveto dup dup neg lineto dup neg dup lineto dup +neg exch lineto closepath stroke grestore} bind def +/m4 {marker dup dup moveto dup dup neg lineto dup neg dup lineto dup +neg exch lineto closepath fill grestore} bind def +/m5 {marker dup dup moveto dup neg dup lineto dup dup neg moveto dup +neg exch lineto closepath stroke grestore} bind def + +%% splines +systemdict /setpacking known {/savepacking currentpacking def false + setpacking} if +/q0 {0 0} def +/q1 {0 0} def +/q2 {0 0} def +/q3 {0 0} def +/p0 {0 0} def +/p1 {0 0} def +/p2 {0 0} def +/p3 {0 0} def +systemdict /setpacking known {savepacking setpacking} if + +%% x y /qi -> defp -> [/qi [x y] def] +/defp {dup 4 1 roll load astore def} bind def + +/midpoint { exch 4 3 roll add 2 div 3 1 roll add 2 div } bind def +/thirdpoint { exch 4 3 roll 2 mul add 3 div 3 1 roll exch 2 mul add 3 +div } bind def + +/prespl {/p3 defp /p2 defp /p1 defp /p0 defp +p1 p2 thirdpoint /q1 defp +p2 p1 thirdpoint /q2 defp +p1 p0 thirdpoint q1 midpoint /q0 defp +p2 p3 thirdpoint q2 midpoint /q3 defp } bind def +/postspl { q1 q2 q3 curveto p1 p2 p3 } bind def +/fspl { prespl q0 moveto postspl } bind def +/spl { prespl postspl } bind def +/xspl { pop pop pop pop pop pop } bind def + +/qspl { /p2 defp /p1 defp /p0 defp +p1 p0 midpoint /q0 defp +p1 p2 midpoint /q3 defp +p1 q0 thirdpoint /q1 defp +p1 q3 thirdpoint /q2 defp q0 moveto q1 q2 q3 curveto } bind def + +/cqspl { /p2 defp /p1 defp /p0 defp +p1 p0 midpoint /q0 defp +p1 p2 midpoint /q3 defp +p1 q0 thirdpoint /q1 defp +p1 q3 thirdpoint /q2 defp q0 moveto q1 q2 q3 curveto +p2 p1 midpoint /q0 defp +p2 p0 midpoint /q3 defp +p2 q0 thirdpoint /q1 defp +p2 q3 thirdpoint /q2 defp q1 q2 q3 curveto +p0 p2 midpoint /q0 defp +p0 p1 midpoint /q3 defp +p0 q0 thirdpoint /q1 defp +p0 q3 thirdpoint /q2 defp q1 q2 q3 curveto } bind def + +%% bitmaps +/pix { /picstr exch string def } def +%% wd ht -> preimg -> ..stuff for image.. +/preimg { 8 [ 3 index 0 0 5 index neg 0 7 index ] + {currentfile picstr readhexstring pop} } def +/img { preimg image } bind def +/kimg { preimg false 3 colorimage } bind def +%% +end +%% Ipe prologue end + +IpeDict begin 382.926 440.438 translate + +% Preamble 1 +%%\documentclass[a4paper]{article} +% Group + +% Circle +% ss 0 +0.4 [] ss +% r +124.152 [ % tfm +1 0 0 0.248985 % xy +-84.7696 -39.4605 ] el +% skc +1 0 0 sc sk +gr +% End + +% Arc +% ss 0 +0.4 [] ss +% xy +-80.9748 -160.776 % r +202.695 % ang +62.7902 116.96 np arc +% skc +1 0.647059 0 sc sk +% End + +% Arc +% ss 0 +0.4 [] ss +% xy +-79.9992 78.9264 % r +201.387 % ang +-115.849 -63.5295 np arc +% skc +1 0.647059 0 sc sk +% End + +% Arc +% ss 0 +1.2 [] ss +% xy +-140.486 -39.9504 % r +67.369 % ang +121.422 241.36 np arc +% skc +0 1 0 sc sk +% End + +% Arc +% ss 0 +0.4 [] ss +% xy +-33.1704 -39.9504 % r +73.7024 % ang +-52.4898 51.8582 np arc +% skc +0 1 0 sc sk +% End + +% Spline +% ss 0 +1.2 [] ss +np % # 24 +-79.9992 38.976 +-79.9992 38.976 +-79.9992 38.976 +-76.0968 38.976 fspl +-64.3896 34.104 spl +-54.6336 24.36 spl +-48.78 11.6928 spl +-44.8776 -0.9744 spl +-42.9264 -8.7696 spl +-40.9752 -20.4624 spl +-39.9996 -31.1808 spl +-40.9752 -44.8224 spl +-40.9752 -59.4384 spl +-41.9508 -70.1568 spl +-45.8532 -83.7984 spl +-49.7556 -94.5168 spl +-55.6092 -107.184 spl +-59.5116 -111.082 spl +-65.3652 -115.954 spl +-68.292 -117.902 spl +-77.0724 -122.774 spl +-82.926 -122.774 spl +-82.926 -122.774 spl +-82.926 -122.774 spl +xspl +% skc +0 0 1 sc sk +% End + +% Spline +% ss 3855 +1.2 [ 4 ] ss +np % # 21 +-83.9016 -123.749 +-83.9016 -123.749 +-83.9016 -123.749 +-89.7552 -119.851 fspl +-99.5112 -111.082 spl +-106.34 -100.363 spl +-110.243 -90.6192 spl +-114.145 -80.8752 spl +-117.072 -70.1568 spl +-118.048 -54.5664 spl +-117.072 -38.976 spl +-119.023 -26.3088 spl +-118.048 -13.6416 spl +-113.17 0.9744 spl +-106.34 14.616 spl +-100.487 25.3344 spl +-94.6332 34.104 spl +-88.7796 38.0016 spl +-81.9504 38.976 spl +-81.9504 38.976 spl +-81.9504 38.976 spl +xspl +% skc +0 0 1 sc sk +% End + +% Line +% ss 3855 +1.2 [ 4 ] ss +np % # 4 +-82.926 44.8224 mt +-76.0968 44.8224 lt +-76.0968 37.0272 lt +-82.926 37.0272 lt +cl % cl +% fic +1 0 1 sc sfi +% skc +1 0 1 sc sk +% End + +% Line +% ss 3855 +1.2 [ 4 ] ss +np % # 4 +-85.8528 -117.902 mt +-79.0236 -117.902 lt +-79.0236 -125.698 lt +-85.8528 -125.698 lt +cl % cl +% fic +1 0 1 sc sfi +% skc +1 0 1 sc sk +% End + +% Line +% ss 3855 +1.2 [ 4 ] ss +np % # 4 +38.0484 -35.0784 mt +44.8776 -35.0784 lt +44.8776 -42.8736 lt +38.0484 -42.8736 lt +cl % cl +% fic +1 0 1 sc sfi +% skc +1 0 1 sc sk +% End + +% Line +% ss 3855 +1.2 [ 4 ] ss +np % # 4 +-210.73 -37.0272 mt +-203.9 -37.0272 lt +-203.9 -44.8224 lt +-210.73 -44.8224 lt +cl % cl +% fic +1 0 1 sc sfi +% skc +1 0 1 sc sk +% End + +% Line +% ss 3855 +1.2 [ 4 ] ss +np % # 4 +-177.559 21.4368 mt +-170.73 21.4368 lt +-170.73 13.6416 lt +-177.559 13.6416 lt +cl % cl +% fi +0 sg sfi +% sk +0 sg sk +% End + +% Line +% ss 3855 +1.2 [ 4 ] ss +np % # 4 +8.7804 21.4368 mt +15.6096 21.4368 lt +15.6096 13.6416 lt +8.7804 13.6416 lt +cl % cl +% fi +0 sg sfi +% sk +0 sg sk +% End + +% Line +% ss 3855 +1.2 [ 4 ] ss +np % # 4 +7.8048 -97.44 mt +14.634 -97.44 lt +14.634 -105.235 lt +7.8048 -105.235 lt +cl % cl +% fi +0 sg sfi +% sk +0 sg sk +% End + +% Line +% ss 3855 +1.2 [ 4 ] ss +np % # 4 +-174.632 -97.44 mt +-167.803 -97.44 lt +-167.803 -105.235 lt +-174.632 -105.235 lt +cl % cl +% fi +0 sg sfi +% sk +0 sg sk +% End + +% Line +% ss 3855 +1.2 [ 4 ] ss +np % # 4 +-119.999 -4.872 mt +-113.17 -4.872 lt +-113.17 -12.6672 lt +-119.999 -12.6672 lt +cl % cl +% fic +1 0 1 sc sfi +% skc +1 0 1 sc sk +% End + +% Line +% ss 3855 +1.2 [ 4 ] ss +np % # 4 +-44.8776 -63.336 mt +-38.0484 -63.336 lt +-38.0484 -71.1312 lt +-44.8776 -71.1312 lt +cl % cl +% fic +1 0 1 sc sfi +% skc +1 0 1 sc sk +% End + +% End + +end %% of Ipe figure + +%%EndDocument + @endspecial White 2211 1474 V 0 1477 2215 4 v Black +eop end +%%Trailer + +userdict /end-hook known{end-hook}if +%%EOF diff --git a/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges.pdf b/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges.pdf new file mode 100644 index 00000000000..a0700b5c50f Binary files /dev/null and b/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges.pdf differ diff --git a/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.eps b/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.eps new file mode 100644 index 00000000000..de269bf528d --- /dev/null +++ b/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.eps @@ -0,0 +1,1016 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: jpeg2ps V1.8 by Thomas Merz +%%Title: ellipsoid_ridges.jpg +%%CreationDate: Tue Mar 2 10:29:42 2004 +%%BoundingBox: 20 20 575 415 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%EndComments +%%BeginProlog +%%EndProlog +%%Page: 1 1 +/languagelevel where {pop languagelevel 2 lt}{true} ifelse { + (JPEG file 'ellipsoid_ridges.jpg' needs PostScript Level 2!\n) dup print flush + /Helvetica findfont 20 scalefont setfont 100 100 moveto show showpage stop +} if +save +/RawData currentfile /ASCII85Decode filter def +/Data RawData << >> /DCTDecode filter def +20 20 translate +555.00 394.24 scale +/DeviceRGB setcolorspace +{ << /ImageType 1 + /Width 435 + /Height 309 + /ImageMatrix [ 435 0 0 -309 0 309 ] + /DataSource Data + /BitsPerComponent 8 + /Decode [0 1 0 1 0 1] + >> image + Data closefile + RawData flushfile + showpage + restore +} exec +s4IA0!"_al8O`[\!<<*#!!*'"s8E!g6W-?=<)6CQ+BVYe9#R:S>#mgkE$ks-Z$O[@\&ebci*?$"@*?#n;+=&Qe+%;)SAnPdkC3+K>G'A1VH@pm)L51SAMNX0fQ'Rc(R@9kFUnsrd +W2Zf&Za@-K\%&u[_Sa=2`lH0Bb0nbge^i@)g"PEEj5f=akNM0qnac;Dp%J.Tq>1- +0!$;4A!s&E'!/9Ll%"PPE_>u +Q^F20U8+N\VPgAlWj8t<[C3QS\[oYq`5Ta:aN;TQe'uq!f@\d1ioB+]k3(smlLOQ +=p%J.Tq>1-F!"8r1!!3`7&HG#qp\H;4J-m^!J-m^!J-m^!J-m^!J-m^!J-m^!J-m +^!J-m^!J-m^!J-mb6bM,`PeaBWDTshCj)s3_WLq,J_-\9AAnZ6N@*;E^WqV'6X?d +mG=L#4!@JP`sGK$6DY"\9c@)mdP">')7DrZ#/7=4g6D\^42YXM5Bq*u('@rOE?/@ +Yn]fi('%I$R10?k_;Yt@K->EC#NF +q)74>[%u^GfMPL.a:C@+%d*8>8i-\o0jt:6#gnKZV!JM4b5Qqj!5Qq +j!5Qqj!5Qqj!5Qqj!5Qqj!5Qqj!5Qqj!5Qqj!5Qqj!5Qqj!5Qqj!5Qqj!5Qqj!5Q +qj!5Qqj!5Qqj!5Qqj!5Qqj!5Qqj&2S%hl"2eeIYH(l2\5<0'5%S:QBHf0s,<=fpa +3`AcV`L"&Jo13bM6s`MBWiZ4IQCWIZH&YQ'A\pT!p8_BEG$.Y<>fEPF+^]Jf,Wh* +e:&`h_cDr[.5_EKiH_jK2#,!W.Y9rUqtui95% +(I*=6+pScHPRc:3uk#&3M&B=OETC"bo?AMOg$EB#uA,O]g@C/JQ,&j"%"Bd>4jjK +:co3ueY?7h)i`NcHYu_I9YcC7NcOlV?0t^?ogNp?QQqk"\Wo*TGBVh>!#]_VX>?E +]'(3+d1g-\L%S,EK4us_XF#djrE=?*0!EeYO+93LJi1,2I.KkAO):(/t[AWr7.?c0]_,+u1n44iq0nKp +&l(1?K9m[Js4cC2]C=2V:HbYcRI^d"cY'cR^Qj[O`(6'S@8n#;,/;9S9h>mia2E* +$q#9KNVJ+cX4-*"b`cPeT2*'oEK]4`gpmc9'>k]!2.,-;5T'hPpAe.Mu\&:q(^1Tf7VO0cTLq:"abUNmR#sfCkGo>YNHN*t+ZXkGY[g_a&R\W$R)e:1N!$Ri;1ls8mjrZ&j#Q/ +)Xk%Dd'7*cM`P6T\hUh1sZu'Q[FkJKr2]YahBsF%&@8Pri8OY^h#<6^ccQJ*]\l, +X/5_4Jo1@#=5?MNAQiLR[HOkno/;'ipR.lFEN)*H,61#$CI":bntl-hYpgC(?/+. +j5%hIeq#@n>,Vk8uTB"-:*E;-`mq@rSEtN;94:mpAT=mafh;ZaWRdYiEnY/9>H!; +()3&n@K;,(Gg'dS1bnp;G3ck/EB?PN#'WA:-]hd,<`)Nqau*Do*fZcC9f@GQ&LB; +d8T-,FW\TB39s>h+?&(RO6kH%1@?mmL,U^AJBFc0GHGTAof8]08N.pGWAi5nFRS; +Zq$GMU8s]=n[A=&4e,2XaCMJ`!5ke2BX-8`t#TTA,`7F(?j6mcJcnl;YVW)EU+Uk +Dl_!hlYiS,A4i,q$F<0B49_rf9[AB1!H\6&8XrQn\umJ2X)[.t-8m^fr:Vfu)BNl +M,@J#.EMXE820>*%8.D;5'GEVsa'bp+0DDHm$PnZA@X;*D=HoRf6&Ra+?Cam63sI +[C4gcSa3UI!^gp)c6%K`O2YjR3Zu?A$6k\=VMjG&%jWef::^<(Qd%d'1a)_-q7Tn +V*W(3Mc_)@jg^4$TX8n\hY@*NG_+?U#uO@U +6A1Dn]NeMZOCl)+>*GAVn1B@t^8bZ[f\?Q"*;Fbjf4! +,W5k34HV33+,39A+P4*O95NGo`r%VIQ^"!Y-XeHMQp`jZ%"G`nWFX(iD1ii2E:$R +]]nNXY.^#s:MW2dq5lnGaW>XpJs$*gQIru2hj=i +4)*#lYp!b=u9!['r+(id=\p8&O1%o<$G>W9OtL#1h:VZ%-^;J%D!q5od,p[ ++CN:LW<^MnP_PE0A/2Q_gRfQjiS?I[G.aJ7KA'pa!Ff>=>lUi:onH:1IQIY^j]7C +!BA3VgpSoLO-c&:XXjVo?M/Ndq^oO#J%Eh0g@41[a%``79(?N'Y6%CdY+q`ue(ca^sXk-1SM+2D]kDWC)tkVe@G+S$nId49cY_LF'*3 +O&$Oqq,-MMK0d$X6"\.EViWoDnp+)73Al(fr;1=.g:pCcg>+irWp.VObcHtpdUL3 +l,dCrmE&j,k!uj]aQH)UtM&jd71I3;8(tqP5O@UU)\18`nc>lp9/:Lr0eNQ^dF[. +TfFRqM"0dHdhjTgUX#9CoGkGDt*(3^PVDmYf$@e0mY]hi%G(ml=l=dTm%)6d"H@rD +Lq__@usGZ?RXqp?8L1NagVh=bq.5GZJK,;(+A0r%c0tB@S]:KWBRl4%6:P^8J)pt +8EO872A8ds,tDuUG2SAda&"I2<8;<>e^M7HQed%u>@.mkmNbTaN +ZA%[C_3)X]%_'<[WN/WY3e@\"eASiEUE,19(Q-YdB4.HobPCbL+jn/#5HIk_>@bS +sr=rH_0!=E\VfV&R1q3@2)Xk:/KI=[M]/%9roD)?+9c@duY!XK_N*>E-64)dFiNn +kOWFaPd;(O.R$26p9>pTs=(os82O.Rl6uKR1)MH(*/!!_10[W'c>`)$N3R6dlq8[ +!!S`jbDN4ii#=dDm6e:_.#>51\\Hj]dl85*D3u0X +*+R_N&](D35MC56KL7W(bZX+cmLes)#1Y8,&m0/"Ip1F#)P(OjiL@.0.:1b9D.OL +V=20/`JOubR'&;5F`8tTk2nP5H[#\]BWok8:np:jsi*c(V)U]S@'6ut3i3O9]L^^ +OO9![Wj3TKYS=I'8g8L96c+H@+hL.7.H.(JF`=G=bCrfom@X"`o11TXKR&L9-e59 +g<4N'QX>TYUDo*\VuL;iL/kkC$[+,b!OnFM!gC%AI!n'l@m:2kBsKB8jb$,766RH +M6Z&hCYS1)<\PD=K0;O4bmSr"TB-Z(tl$IC$(RMU>1l+<]48Eqk+PN!dVat>L#fR +D5FRa,T%BJRT:CL5\2f8P,hJZ=0g]-/$??u/NmS:%?[57@($IQG?!LXINR^J6$Fo`^(Yc +>gg3'*OTBrfND!l3mAEU/ZRb?`b;Q?6lXVG[omepIY9@7OXg'a1QF!<9D=X#s]** +`8kW#M>inCtH8iI/!Q5LkGi*O&:`mn],%?)AXFRNr$%Op'kG!4p@Di:\#cCO3=MWHt!\HeY#hqrthc +rrCt'[Y>IJ`uK>g8F4*9#ad%'Z/B,Uao;A,=')0p;=SR[(/UHXC9\Rd.B!H8.q*H +cDVr6.`cgoJ44ZF$P2bNHN[\?P,7N]c3e>qSh_&p#*QNK0EG*".OK'V"N.UVP]T_ ++j&p)>oYHK=N(l1q%3/M].g30n$-#N(=8NXOioL.C)4o<.S(q_T*8@J85^6<\i#e +V9J?NdT9!QG=)[bTqOAE(5R-]7$lkCQ[!),r_=7_tA>N.M>nJihT)%r?^@'V!imX +p_HrPJL^'35?C(ijH-('l1Mq\IrS"Z3VLFRpo'Q8b[P1j!5rZ/f5'R.upc26DfuY +BS\] +J9Wo6GKWU!$-!8pmIZJ.422md.$7MXZ`Y;9=!#/:!!#/:!!#/:!!#/:!!#/:!!#/ +:!!#/:!!#/:!!#8")eo]^P_6:7NfPN4,5PC!r +gAduS?&n"]QicW8Y_Ru:S.Q!oX*bg/CIL!#5hPI97c`Ull+7"uOP;ARmO_S[k8m]mQ:T"Zq9R=?GAImI`uF)se +oM;E;+T'j(\8q_YSfF;ZB(@sSY-CCE2S;5Y'27/hUhAJ[J+jql.aA:=[QZ+An"YT +m*.0KJ-":YNJj":(gb-$LEe.%OsmEYKL9W8/\FNimR6+ki"B5oO>:hjFp9n_+ir-LtXZ.:4f?KE-cNfVf\0/[tM2"D9!Z#+@)^TQ +om1D>m*8XXDA4'ZR":EKC/o*"Ath*Q'.^-^$GB/hU;97;oreHlPJe=tq#XPJB._/ +d]kJ#$Acb`XA*WglA'EG=;>0a9)r(Olhet(;N(Vm2FGo>.pK!q>QGsCMU;nQ!h%^ +X4bA(;j`Y=_!H<1KCYlp5Qm7[0"DD$(_n9TU-uK"f^IrY>JMr@87Ml;8A%FIp!-@ +U6ZiTGMJIJT&G]20ZUFqIcHak@A7-?&"!,DbARrUZ*4do18$Q]/J<+@2ZR,tL1E8 +Y.>c'Ra86dqB2!!H*rVlfs^&J)J]t-;+J4XYtUp7AM>Eec'"]4Y=!FPpfD9!p_I& +4&$C;$tiio^`34i(\BTEMoC[rQc(/\/mKL13<,A#OG_M\Kk>#gs\/a6sl(Nn"B)N +VnqF,<-m?M#">>ZkH6t/puno:RHOA5u?29,\.I_%bC&`#gQ\\f73*jBXR*&Vf]jA:?@Ei'f2`bAV*4,F18)&t'PW0Z.G*%#6g +Y$:dCuX+g7M7hr/K7fjm78g<'=NJ3FZTEQ]\#V$[6)gJ6Rg(rdZCN/>oqabF4E6G +rB(Nrl6*";D9jkpfXBe:QJl_grb]l,K?MNNY#BHXe$R:?a9//$ed+FM>4K-9KmN# +Z5G3>Aao:D+KPZo\nCBi8Z_`'.UgoR*58-NJ/5#Jk9$Eb4qp#nlt+rGM=m%2tuif +E`F@a5.X;V1o;FGpe=SN!Z='?!TLMi$d +fLUVN)hhKUKAGko]1Sb`[SB/nPdH(lO'^XrB=,'8^O)A[G28OJUt^JT1E%ne3f\5 +N,+g>ga_mG$?.t,enI5$%S%Q(d3i`=o*:Ci)!U7Wi/5#u(;1[]EAn"HQD2T9TXqW +[P(E)\n(`hp&[,8O.]r^Y)pXac\DVHa4Ai)EsO^./f0^j:^;)A4PW_#M7!g5_J!u +]BFqiOj#4V9=6oc(.4RcZF/ST]71bIUdr#eZrYI-m14#D+o`-Il8Nk2 +DT:DL0ua%+L^2apf$P>Q90A(Ot4P>oi^?Bc[j(;[`.n!*BEepTo,BWm9qSFp1sTrkid +qM31h!>5'Zm.PU*&2KF'0d.-CicBig#V44o?0mOE"rU$[oCrUX]`NVipK9,1uRSK +rU+S+HZhIY33;B"uV@gjUG:?LYepE=hSl\b=GLSK['/56kR\rs]"HDdcLn'/$f1l +Ja:=gN#\l$o,_\LE8m4SOX:4apBscO*H-+Eli)n2/R!9HHH/69nna4CiNRbf:1AY +bt1lFVs`D=RHLK[:Or_*OUPOAm3@;ZqAYRD`#k,-Jju+*':fOJ0F\%Lt#/ +X/bp:\;dqpb$:,8M_N+\btUq7Pm$`0@/.S94 +`Y8KUj4"?8gf!Q:PA9G@.EA0@b(=&jLl[hD>3'I0.Bun`u^/U3/b+ga%Tc!=HDCe +!o::.^1TUM%Q?/"scBXR*ZYZg0qlW(9$D07Y.I!Lg[>V_rLHaiV@W[bKEEL$DHZ: +)mH:&?C?_]ouq'g:a<2[SFh8.:^$_A:lP>ee9pXi$1*_>qQ&K +D"-tZbb0Ft>^(NIdNN^2X<o +m5qsS4mYa'5W5WWSfdG1:cY5St-+s*qdtV;rT^Mi3c3[*\4o]=M%\[d/c=u@t!Dt +*p]+>BdTe%C;C7MODU(r@f(ub!)Lk0@jd=UHI%c&?b5RoEhHh2h2V\an!;9_KkX$ +l$BX>IduS/+fmLBp[*t@@j)'jT]IDm#&&pNADOGRSFksd[@]M6a5ho?!! +2>?!!2>?!!2>?!!2>?!!2>?!!3\HRa2F?ekjC9W%o3q[\X&5EDGo('"cc%iJN1[m +&D>02VZYp#`CY+H7ttSt6H1OX6!#%FIrP5'E$$]%"u6]V?@/PPg:UQ4\iorqY)?>9 +oqh8RQC8T_a)ZUe[`O>6@@8_O0a$,OD^j!D*_Z^Kkf,0_=CR6)oL%$fe_Ocd%B!$ +0#=ig)*?AQsM^=ft*9[Q)=agD1=F6-(>MmEL:X7L@5GKOPfFo,V.-\]R5"a:!8uA +X'>UYOQ6cja#/%)V;)h;ff^sn?^kbDh#+I`$DEc[F/\m#:UKM%+3/8Pn"+#,\.O/ +\b!>k4;'P2m$?!)DIYJHF+Tm%o.Hu)VT/5?:-+Hk"@$kU#$P)ZKH>D9I]Wfff +6U_3`F!-0uZ8c,9[:'hE!9/pCdAX#gEHJ15b,L>qCns7B[2G7S#aZ.OQX&eDi^WW +g-n%-uUS%aN\.VuW&1L8;26pM]q8b8Dg6jEjK"QP'!@Rs@d24l'cWtB&%7jO6?qb +g">AW?;C'i,hWO.2)@/WOJJQ>(1Kp@:a`'85$O8/W((#6+\_,a$Q9J9nVj?Jk-'# +SG$rq2qBtGHuk.3<8U["qT(#d]oc3-M5kP=-r_ueZHD.1h=`\;Dc(AniLMg+`D;- +/EC]pm_S0Z?^)tT^c6>@$0G6NGE-oN)KI'^@k$7odhcg:L&A=3TD%f +f=X8]h*lW:RA?\N5@rc@6QquB +TX:o;DD6-s.\q)KlR(CsM'I!0.8,qdeI!Kl\?VA^$N0;-c:[W=3>c.E.V8r=,eB* +T`>RHB\S[0/;!LXS5.P0^LZ+$h#c!D]Nd$cVQJ"P5S_eII]?uWQE23VJfn*!_n7C +pdgJ>TS]=+1,^d>>tf+K3<\p2#M4Fd`C4!?,9^iEN>.Q8frh"'R3NZTn%"$CNTrR +&K?)Jso@EW@*qa:>i(4`T6\q]iJ%I +$T^G5&@8Y/r.ZfL;rS36,;1jGKNYd,Eh0"G5Jj$?`2&iI\8UYE36L(UQ#R8cgn)* +'F*X-:e)C"ER,bf.ROU_I-ctPm,^0$o'U[c7Z+_Y4L*%?Pt3kWo88V\Kg]q'\nVe +2:urbVYr`UEQecX@QfV,DEhab@Ob;+-,iYn+p +T#C&Els9E^R&YBKi_[?.?NS['ui.QStL(CW1E"<:J^4io[2otgAM1`I(:H2%2cYa +qq2l3iV^Ou!!:g\%oGe)KBL=TV9sd6s!gEf_+joE-gu_s]7-:M +OteNFje3[A(%hL2#c&+5.#HP"H/QPLW1p2(%sRDqXP(]`.t+.f#3raXs$^fVaGL8 +)SBM0Ik"%:#kKt$PE)SS8P^*g=HodYo@sK6^#?Y2e:qhCHC!U:,\S=:>>!>hePGV +Xo-mHBjY@(`>W+^NQ9bUA;`*'lNnaTnqBQag2MBNQLE84?$eiINc`dXXZ#/C,`,n +11)+.^g5&Kib@G\O,8KIhi=#Esm\XJ9g!U()Z':oB!I>3R:(B##4\m(K9%2btUbY +!d>V+I+i^b7*&7Js-K$;"2fI1!+,q^pfA^^:PWg?@(g6U>oBX_;OB_T2&4K#$9!A +9)_Pd_I\G8as^Jf,0;_mT?(V8dcua#uT+&AtCDNoD/IULT.BaX,0mV4(_Y,6VOiB +ftGH!WYT2&5;8%+Elup/ +hu)L40%hGCfJL)0/$q8D;b]l+tARrr?fsD,-WQ2_+R0F%u%tS_`"3:\;%*-%M-S9Ctupe1:YUh@HoD=$GO0K/_],_-(Y4L;1 +NDVb0Z>Z$Oo@UT#^-o\So[skd[RRnm494#:^pFEeRVL1T)@(4VcZ\<9.9I(2l1i? +Rh#TWH^5.,\iL6>$fT3n$aN,.2kF$[k9,L]T"ZOq[r:=YNfo1; +r2nC9r/;:nH60D"XdbDt0XL-lD$(.qG/npT/"\cg(E-!*G,:G$aVpQVC_,hk8Ju/ +M)"mHo,P9$*Cj13S]qC:XbJB+&hr:/M6BJ)7r%^UAE3'1t0#lFsWBt&O6e=+B#F0!MXPEha)>@hfq+K6WKaPcQ'WstEc%11( +A'Uj>^9jO[2Xp_/!S#qNgV#J^"D-VH?en2K,';di\5BL)k6-oGB?3bq)kW]L!hhP +Cj=)h=M4'=qfdO3`2)b()BQ#NDSYj7mUhZQ+rnIj\AplbnI"8'\"J"I@ONVkGXX^"N$`uIq +!B`M9'cq:>_1qCEK6+g[Og#U"bO#U"Xd=K?2j0FB5&J-m^!J-m^!J-m^ +!J-m^!J-tj3Ld)O2Gp`%CMWl[uYEnni<_0'Hic)[JaTNAG)l?WA_Vq?dOmruc>g& +gC6#Cr\:G2)h-;0QH@)g?6"6RE_8B1iT.amt2Tb'jA]V]D.jNJ#d5o:Ut#?-eqi+ +$K;Y07=l`'.ODM,Z:cl;)b+BO7PG1"5#o\kc5.i1k.tbH +?8u4jAb./<=+1DuETNm12F&k+G2dNK)&WNK-lP=T1]dD[ngZK*O&3/9Hm;:.R,)&fk^cT25tL+Z"?&BN3R?M+4%L(7ZZfGcYKrqH4 +hWMGRY\:j(?L"gE$LA'GOfUHQnR/n7n19ABfqJ5`\Z,H/=+lk8@_9Z4M9KG*PP4g +$P=#K=HS2VSFsaX[T2UV`2Rm-jh`@47$u9m)o.1ZVn3#KQ5M56H+rJ:mGQX`2Z2$^54aRJh9;`5C:Kl2j3 +.n8=S$Ij5e(>],nNDjR=jt]Ml^[N3F0H,&OLE6Trr/+KCrmQk2#m[6g"k;mt2B%$ +i^)>fdtoEbuAqTcr)/i%Q=b3+)_m:,9@2'O"5>p9@.h4%i\LbJ`8M<:6cc5>If#Nf_>Ka[f +@$ui5qgU+62Z("N=.C/5pK/&m6G*.@0$"h0]8NAdRSZT%pFW]jc[D/iW*h$=_R/Y +QPZ-.&BMUE31eRqtSpCR?)]Hi-F`_[:%jC+AhgT@g,E<8l.X40fo&Wdb@=;5o`E" +"otQHAq/@_&YS03h7ZYfS.cm=Tg^^H`Q +I*!*u7Phh07StCU>-#\8\U*Fi*s585:!c!Y)&K-riCj@.8#YDJlp9Ri(u!_(2g +D\/g9`13-n%Vjr^FgYNgF870QQ^#(Y[ZC?2CfK0M?h6BU5)hI7n(k\>jP&7f_?f1 +j4Rb+bP95u0n]W%d;_25nSkAJL\/%"mFTK.IpaUCJS,4F7Q'so=X(NN#/a3L^G&f +H4:^G')IOn&o&8'(kFP;T2T_;A_:S>"pFa>\VT$3IX<.GdA,)&11;o)s7-=B`TbO +?@G>f8n3,c<;nUbe^WUKHtFXe'[UUp&"UOI_$oV#buK5m3@J[j[g[]AW]_*PAhf[ +40HB60Pk8%[iA;k[aIi$,l:$Z9][7s9#J"R#3*-)Od3cAO32af7YD[3e\XqEENPk +% +cQnKdMn,4Z_sUsB,QjR9lbWC;DqJ_eElLN=7h+NTEP/n$,:"ns/:d-b`9kPK0nY[ +N58BXFnCM`\WkOC5olkT6CSfRaKgl]%,F^_bBA@?@d@/s'Or9icn$d2f(B_oY40d +,9c=sjqP`95WqJEX/_^&[n26^kH>STe\E!GD++QjU7""(U5K1+02Q>%IYlQ&V5nb;gq]Wm.ga"@!`B&g#fgE! +4FW7QcXoRjVt#W-Y6l$;/NiqDP*6H\guIQCF1WgKl:!Vo\8JNDj[)JjX2,u!uN&) +Q9OH56(hq\>JUHjaRL,&QFNHTYUfW>kIKN7qGoKJLik?sk+:QO)fIBZR4Nn_;A4S +^"p"fjhrO=r=gP0Mf+D94H#kg)#ti(3--5DX6&ZRBRE>@WOr8.UM/HFs6B#8B0:( +nH9Ab6CY'OmB?[:B*!,6-?+7\cV>^V=LO.:^4HM$m3I7M8^c+4973M^o_MfVM7J1 +fc(%'CNdj9+_nE"=br(tmY6e-dhe./P:UIi,D5tj +kQ^,AiFT\9Zh7O&.*P8`8bRh]Z[ajsO&,KtY=Fl!Cfc>>q7AYud\?sGY/E^UsFV7 +6H,`e8-;VQgDkFl,\E�&E-N?S.":$j_QGI=Vi?MDpNlt7b=]ibKLD"jQcu6b%^RFASbf_W:@*?GdN)>rC?k6Eo55JXJmHP(;fB:WgQYGQ +?[bPC^\lib?o[<0[d/F).hbb1:=p[Bm9Mdb!eVW@O3Mj12Ed)6Dn\YlH>!NA9nJm +rj9WFjIH'%(>`^g`(MYPO]uCD#8cJh0^^Gk^>tP`7B,:?.Q1g^=FY?Y2Q^NSY;8M +Q>H6?#H/Jt:VBE--J#YLcK@+[5'!h,%-Ib+#CnPF4\]ui:/R9Ila?D8,lR/>oBi< +Wr/+D:r^H'uGjZ=.@aB#sG2iUa6:fls`d/R2;>="diJ<'pTO9`W?n-\h20?P/]!8'Z#.gr)$Co +hHMWM^$[Gkr@qBRkE;dcrSpB.NIlahkmJG(00C9Bk1<1>_>S9Lgc+nnUF3rGf>ro +gW49c,QgfeEc\8]ScEK?KYEc^g_`k.b8k^3%u>?%(dFPXqc5;_,@&_B>>6$@_LnJ +hX]Od,#3%X/N\KCl1m/=+lPf\[i4J!?ME*icuX4'$tJ[ur]URRTB6aiQYVq8[ruh +(#b8\mVd7EtJD9qi[WO/@EG53Afh>GJ1,U]@f@FYHM4=1F6b;h59cbfV@RVM1f`X +G!QSLY8PXj\rA6"=,=4['&h:8e2!=+L\H<39*LCskF?q8ir^@tcYS[fI@^_0N]7, +S5>hYtZq(e(nr-8W0bGkTi,A_n<+9NLERae7dSl$OQ24de43,rWhrHWU(Ndu8nF+ +:/2P5K"WXg]MO^8EbS-rJ4H:-8)g,nN6a<26cYK]>%k7qNH478Z?>'Mng +!'Mng8Qc'CMJ&3k4rrAh.2&iWn[Sq-M@ri^H"34_=i/H8l?T@hq`^du$N3"j_).o +";$TTIfUl-'@bE0#`g]9OqN1W_!7TC`Q0Qr\q%e&Jd4^>#u$-lY1b4Or`esc;9pO +D7F3b0ahW%?/l1^ghog;e)[?D&#ncU6&eqU\EL2UKK],f-/`,,ATk!f[-Z+U?15I +F8^3pitl^WG0r'fL@2nQH:7$\H)[[1BQWt2W4kuc,u':f&`Dmp/a-`9Oj;Wji%_s +NrTciar"b:D?k.+2\*@$DK_r$$;IJ<,d%!Y[^+cY90;G,p%*/_M;i;C[9nedrrCZ +JaKhCCbkDmI"S62]JTm/ofFH7R#6tEji,i?DK24CgLj\GR`$0^bR5;.9ib-K.\8l +crOp=<#16re5$j+B*OdtNk5!e+p&an;r!1F"g#a* +gl+"ADWi%R.6*!/0\gBS%rX@*iOVgFo!@2qgA=[>I^!T]l`]-3"\#6f-%!NP6"9/ +CI:P2fAO@d)f#;DZ@]b(e]M:][qbG(P%J:W2":>5g1)Rsjq^BEWA#$mKDgOd3<8$ +Q[diM\K($./AE6"3=BpGhg)Y'i/Z.f;-0!]mk:gRO'&G#Rc!bWW)siY?GpMgT5R; +>"`]aR_^*!Xc!5u'pnZGNoJe_c+(eAPK56gb<<:F5$Zglatd2Aac7Ob*JfXpV;$U +B*VLW,&kb[l>K`bSgq#,,X/*pWD(9t&$WA(Z[!:E37RF73MD9VlF4^m%PEi/lhF, +\&FX)RN/Ng,365<$BOf2MD"3\RR4-)!"3Zu?6Q>!$r-/9]4dr&[4Q3$g,5<Qk6 +DhLepNUfb)7\oCZe_)G,#Yf"!.CA2?n+7?m\Gge366;X=P7<4$qJ^R9"TNB,9(1+:g6>""L0'V:Zb9#L++]Ja+(m.;`lS/h^Z1//uS7QMU6 +8fE<]-9Fed=c8MgtYRS[M>7h3>FXo;3>J"+S?b]7Bos<0M:$@HcU?"k%CNhNhmT? +V`8=2HKb@dBAYsO*a\6k=+'5lMC[bKkH6P;1c_G2%&<3m4J:r&F=j>"L+12Bm3@A +d;F2=@5ZEH&)o)&34Pb=3HF?kIuiP"p1TC_[s+Q)AU9=i_^$l +j:Jlhn=7icR"I=C$"uX7,>DEdT^LhYJ4WBom6Kf?"WG#K>NdX7R+=nMW6.jTFlY: +r7TB4:HU9U[P>cWF/*Y^U?IQ\*&7DcPs`X1I'9o)]9r.[*=8fOql?#cDKS*.`!IQ +"U:/qj"#s:(=L=#Y!s^!0!)S")]1B#\7])BMD&?5\Ej:4A,;Gj=ofEK+`OjB[S:WN49C8FR'uP'FZR +.aROD?Im^=5Lr`N?F5p/;YpB(Hm-"j/k+!F12G3R6%I7;lXJ=;#C0P1=#\A%B6d* +0qibFiu;7*.h;Q35DIn-(/UVcGjQ-ZEr8m_]*9Q,c8G/D?MC3EuF#P8N#jC1;"A7 +04>!Pqcg\.dWai^b1>/>3pu,Z2"d+T-+cfPRc[P!5n1.0SE(*X^f!_d$S3fH,=]"RpK%#$7 +b6lNK63\e)>Sk)9M\?/WkQK:aJ\+b5,fEfitrFr0<^Y72!Pj.3+K-_"1e ++7OCIS:g4+#>iE9SpRV.kd\XXinls0.X3i5pN`BCUN5u2Y#WVDiAU\N<`_":rRmC +g4aM!&'ei9A8*8Xn7#ANlD/RPmjlcIL2:9&`;BbOsq?S%o]q[%B#.)S +=[0^99F07k#hf-K`.GqnKnMZ&$\lXM=,=Bik25m9a-7,c^MZ^%?m0ID?kGF\Lp-- +4LT]+f=]LFbU+hb80EW(>6sC?!qGgq5bi#.!$0j-kt8"7]VP;6md0YTr9\h_]'b+ +aChK&,>G3UZJs6L)BXIn@4G1#@m!aJETt_Rt(ajp`eQqViJdI(t\@XgB8\c/U@rF +g[6LEg;i7X.M8@8_t/#Z]CFpk+,$4,S*-Y^@)]nafBDY^=0*\2Am=&Q;Zk#j;_Si +Jp;!Q\a:p`'COa!6_k;i5U>ZFul'>0V6)NG50>UO'0'DZ%fbpq+k*4'G:-`M1BE3 +% +bFC\He8+J\^pngqdiBDp?3Y&MEV9/_gML-t1N.Jod*$&\pEQ8mWjmU"/PmAs,G+M +Kt+"Z%\$p1.Lg8_#joQJ\aI+_!mr$,VmDWUI?Ke/!C[#5EgU-)FAo@&-^hiaQ\:l +frrY]_(8!(M$;'TQVQ+LmQE^1ReJ+GLIfnPW"![\2k9d$o;[+beooS7/o1[aKD05[o@mMAp7'64[EB?/:rT/ggF%u86^+(O+9R7TT&)91T=HQ*DZ3\bf% +&Ti1i1Xj?Rj@T=QPO*e2)A32Cs;s+"F82ai6ML*hK*oG;,*'FLXtUO(a\LR+TH>E +K$/#am'DAm8cW<:DAk.1bUUm)Bep>*.?qi)$c[Bo\ec.0aVGp=t-8!.:sHK9UkT> +NPI.\O:OKG3UP8"8mKu6Xa.%Uo%)"9C[A,XMq_DM7sgY7RUn+0(#u6Wj!S=)`]kF +MOY,"(M5RZ[`!;XlORaR@YJsYl^5_K^As!?jXl'2f3to9pj8k4"SUD +88:Ung\JKs/U5'$m/*O398Ed/HAI4IprZ>%S>HJ\U:RoWfQf>pMm\nM4"Ku,SSbZ +Yd$7m$bWalBgYS;O4c%$F7(gh'SU:jeNZN8L,)pZ)q@'kF57E?nIUEX>!72%6ahj +6ju&'D_LpknI#_EGT0?GodfpjCAZl"W/I347gcC52;+H_+Kkc5F.U`05KnLCtSJ4 +8oCe]G..B:'g'.VMW)7_=8LH,DB_PpXWb)oaWYM5;VtBb!Sb0P>#N/XEjEXo;,i\ +oAmCO`pHIgeStu,SWg=:8D8_UTDZi/rb*N^>aX7tIC]]$1lWVc.2Rt*?HR7QTdV_ +k'mnY)gQ)BdH?Q_b2<]GNKm201-huh#;.Nc!m;7`c;(aWZtJ?\3tY9!/Q4_j$2`a +\Ptg9S$P1;JbURHM;/-_A)46#dm'?'uYnALJaeja]M1^`NLUrF&OX/>5ekFnN?7X +h/@ke3-M$P^0?N%Mt3C-]WNP4Y&",g(m2Qbk9JHPD6ubjE>gk3P!VIp +[j:tR.\UgR+AbD0;?F,d2)(@JP(V4Yh%s%nmCiG,YV_fup-49Q4eG]>-n]n>5B=Y +^Z!*rK/4`;,5l?,i>]d/ZYE&5aG2pH.qJ$f:b_YOnQpTP1ORn%q+]%'Sq\$CbL\= +_Z-pM`IlcZm3lFJM!2UaZ?FD!p]Vfq+3^J""/9jd#s;+1_/;+20!;+20"aa?V0T1 +&0rnjC@i1+g.L`j.6X//_Y7JuZ_^l79]FSpbAQiS?)=Yp,nnECUFaJ_m5h2.#IL3 +=8(9/(-U<)lY3h5@U!_>!gY/H*mBTaME%`MukmIr9bYfTBKio[;2N->tPcEntJ?& +!Mis/E([YpiN-$qalHW`$GLOlR2V70]ICHLE.hP(F:2JNW\6F6[NNthn)2XEs_8oUn!;r2aN ++KQX!pb];ZEnfJp=RdX&B?K@3,)toER1SM4ESmd`s_(T$.LQ.@Y@6aBSHpb`C.4c +OG)cs#gUs<_[fUCl5/&1E1KTLRI"@dSp;PhYd9=JJ:]^/a-k\Bj#F08V^dNp>rJ7 +^:"_[U?*-7YV1fg@6YRI1 +a`Je3-lk$]Fg2g/Tpla6Y_*(#b&m"T2`ld\V"heCNR&ja_P!i+Z$Y-'sD2[!HGfF +otp);E$F_`BWU1kTmc;OkC=cZ=RQ>WL+\Sc^1/E$DBUgRGUUJEtf164-FWsiQt!! +86ft$BW"Oe?Q9lRTZJY6kQb737mSmJpGWs=Q_'9i!tI1QPk[YKnGqAW26B&H +7O4*Dnf>qN*Ms/;L*SBXH6Sc6Y/AX&U+>&B6,g'UZ7R4Rt!ej,BcWla.^V%1iWei +hT"6D0s4>$.CGLW!-4ki+#YfM8q:m2]d)4pE4jZ@WY%n1\H?LIPEWd&CG@[SMhs& +\X>ATVY8j9@JWV.A:dUjmaEF^?6K*rDH-_j>pn>VCZOm8!O@&Gm=!o'5$U$P1rGb':a'2c."j@LK0?B(h]0);<%canm +`t5rpbLgVrU_#=9fZ[C<`2Q4tE%2T2`D4\qA1p>Bm#XPV<)U0u``m[j`heSIX&19 +SmsL>Dmng9pRF]h@M#i71omP"/n:`E3+V@a9$m:b^86`IG-f/enuGB+=XTo?X3iO8H3K7Sto36uY@M@1j*QXb*O;0Y98Bs>StjKHWY0VsR7N:tB8c?.H/'^AFtuXnM'r+q(3TdZW>Lnp>)I=g@\67V.R@0Z.] +ME":D?.YS*1PFRhQXi+g@]"Nf,BiE//`NZ9m_Qd]\`Ng;13q:NsU1BE; +[Y-@u6;i1B_)0#SBDOkcOr1qlK7I.&g`hm:Uj\ddLkcFbT3Z74]E)qP2%XQ8f5H[ +!r\fe$+0p:f;9@?;`B/X`uS/`ar$MIjJY8IUIR8dg_O3T7\`qUB-/;k>srgSj'9b +SLikADF9ACls+NUb4nln'4JK=cQP4,Fq_:?t$Y"QmXY.N!TrQ]3?6ij:(XiA5mO% +=sg.'g.'ZA.rMm0gB:`4^lV^Ar8_C\Q+/313Md\PFfqbE!.4=Op>4PA#&C':qJof +8lU!%<4LC1VdRX[CaXdOYcZ\(E,\uRN +:8eP=d?aMD0>Q1`JR>3[obD]ODnH@0#%-($k3$P0:lHeXR32,k2YN41DYuZ&.[o_ +ME;kX3TPcXjnFnRDrb3I(7tAhb7%:m6p$e9!"-.PL2tpDT20dU8eR;qmcrLboD/? +emB*sYXZc$FrrC2qj'/:C9.R'!it7W>gJN+fa4$t.dcN'IVVi9>%$0fU^H=(lm[^EdFlD4+c%[R+p@q[^H( +7cK&>"cB,6A.XcPjL"=B.;+:iK.ec\XEM+Q@!8oV'\b#A@V[DcUAuZ&-+((8aF]K +PO6t'E\c<<$X5Rp)t\9A55Ts\AN`Ke$1$=K<5C67]/8*eYF"h",&$QB*F!Sm';!k +pmuCkYPEU,%]BO`^o%SSqRS(i-U@KhWNfl9TOP.G/fS6qKgedYnGSrg!4,;1*XqP +$Ke$O$,a/PK)BJ.&K&j'Zj3>I8hG;J1F"SUb5Y3"*ccWN1?bGW;Q,Kl-&"I_^KN, +L<>G2jX8SE'C:8%dDpQ$K$RA[QS4Pm\HN<<-T1b)N4g`m^(d]aUqR)E$NN.me!sk +L3YlcV(AVOY^'FAb^/9ZaYqI/?H5A5[eRo=-af1J2[E-H]Z9-pSZf[`Oa)Hf=$dq +TO0^TLl@kqL>R^2D!1>kHc"LGgU-!RVSnU&g[%9$P51&FaZ1;,QJ7Q(n-2B?dOYs +I/=.Gj8%nJKR3YU^14'3imdr*O)=2.*)2EHOnqBMET9I$&XmLK(GHX#uW`!Pf<`EZc@SGj%bI$-,0ua;N9J`XNe`%meN$XlXe!5q>/Mle:63:G"6*doEpmXRY(MgHt +8"&"@r"-K%,Cc2lkrcYpe"3A-ZmJ`2HPR.IaOg$?=UVm-*r;sn(:[TK>b0-TE#BD +]ULSeY04ICSJiOSMO1XEPsVLb`/!OaaYXe( +Yq>Q#QfYOp#(Cr4N-"Acfh?j2;;@LGGKh8bk,/;'-qkV3gh.W`>"8(q>.(qel`I8 +\=6k&':AZ4UXKa^5PEYh%XrY +.PZPt_[$>Hat?+6@m%RoF!&#WOtn*:\Uk#Gu7COXMi+(2akD`u#lT>lHU/jD:HRE_b.O_ +]\?mc2If/^IiMqf`+p#3>N=5f&CMTr7jV^]mqH_+t:K=6Vg?^DZoi2 +]'?=@82'Mng!'Mo%\IhZO[q"mq6q7MuK7iR3\E(2-WV+B@(-(Y-H.Cj2 +`c-Y`o04*rPW"IMHMT3Z%RVHik*ID7Ra]N\cQUb@L?<4MN]=nc0Lb$ub6tjDi2j" +-!3HK,LM9P#82iY;P43g@s&smGEBUctCu(=@L]lYK(]ccPC4OOt=nJO^0:doE^@K&1'e`cf+k6mX*&,tBloM0%(hY2O>ipE5hj?[*PC>#hl5sqPrhalCTl +R'GJ3rNS_P?qq]tne[kTDj>qCf;0;N9X7jB:\Cie@6%QV4<1m:XUNrqeS8g?eg,o +[T.%Q\0YpZ5+8">bt';W9REl*(Im%_UQC&:!]hP>l%/+U4h$ru>7:6_1nJK +X`um^r)&N@c875:g@%7W@(aRY16N'NIif$T=XH/aH4QRl:8"6J<-=IoLT$us6n[ +F6u\3&5"&bei[(HBR&nmJ`N[6%Ssh*ZP!Bl6MEcQT5+5'rR_Y+'onqBMREHs9Yfi)NdaBjm2J%L?`=6D.fj#EaZ*>:^=AM`j]2Ap_ +JtD-3lSjT$nF8'Fs*AS,A2%g;$?/>X8Q^6.NA0#WJ]A98.h$scPr+7Bl6TR]+c.4 +cUO[!&i_3l]WEO*?f]Bhj-NGu$"Yk9QQ2c`^N=-"eVj5*s$bf10\D]%Y44G8I#L( +G2@4SKSnO\5>V?d[Q'I2hJDHJ:^r!q!2[";`dT>6:u$%JG +'eS\#V&+G(Hlo>n]Ik-HZ=_^2AJ@&p,][$*\:jog[Q2p(1#+cnW]N"ANCpoAmSqe +a8qdV1J<_KF((pK:V6"8@qPR1M(>NMis)4MO^6Bfb'VlZ$%[LJ\t!35_7sX1ROT_ +8b<,%/&m">#1;7>rM,Xe!BCo[`bTac-ug\mBFc[OVIC7[uSsLNclp8AN]=LE(:b+ +cuQm6H*-G9-V,0(#aSs'[aIr,a;!TuR"jBUlC3htcOWV('e&g9/2sY)UpcSp87N' +"b;h2bq1]1_\/d<>=fmTsa`D+lk==3E+&J5'09gR7AI7(3Jet]\RN"i_Ve>)(;V- +&>qBao42LE'7/u"g-/]ot\Ga:03*.5TP8.!R20Krim>B6&pAXXQ2D<7=Qq=dT)j^ +F=pl5><_^`6i(?icTi%Gg%!gYM,F'3^Yb>.it8KH-q51#YWMjfj/K4$pK?AXcINk +\=Rl[b9p9Es,u5/3C<"!?5!\4\dJ,2WEl$me$)=FSG[Hrn?F^m/]tqC4QGRSj=a9.4)d`kaXuR +tL'aMeUNS2t&LsME]p4.h`OP1;3?/NE3q#gu47VBGee&:ugF^9I28&?u\Up&NZ,5 +r+_`0[:RNVRlYF9[Io@EI'e,CpY.'?3595EXtkr3H[ +]jIKM;H%k>)jr:NO%m0J&>!V5>=QDjSAnC=&2[*ZUo9E5U&\+6T7mD#%+qP!1h=p!ddjg7CHE +'7^(o2U<"B/1>jgSgos6QC@TXP83"`U>*f^m;b%[kbZOEu[2J-eg0f^jHS4r*VGOL +mqq,bAZ:YbT?^aP$[Q*/nATD]%Dn6$Q9hl"5[d51%\im3F0:4TZB:DSr^r+,+d-4 +4>II_m\1&8c/BI#r:0B)[^m>akaG1(sa3+08?W5qaS$/=^4a9K#g5(_28F>J?=Bm +Ym^j^PM;e7G8pP7Ju+C?]Y2F4[C9/N?CI9Ph33oDgN_^^812r8Km5:EaWN"6O99$ +I)nL*AN0$*kQSVmRi]B,bN(5XKXO4#ghug6:HCQ#^+%gYH25S6N.pBatd_q8+$$f +dG*0*%p!-Q::GSm;`gU6.[7m4L?frK.V_AncHS`#glF-!n-F4fWf.&broVV9e67q +B>^pYOKQ?UCg>,0#d2o!;e.6r")-)nHTsUuQY<7Qu?R:Pdapn3i+P>bNS:7jASCO +peMST\u@04fTZ;f($A[`PTdEZ"lXKnuH7_L+6^UG]L=W*$4eg*p1_CB[RiVUY8?. +a;jTh_RCE.3$Tg:H91-kj42Wp$MJ8sG0Q()g%p"urWgSMXYHR6@mfCMh;1<7 +)WBI$u("$A58Sk0m40@\NQh(m.nElE!OSKos%I'\mGZjoU),Th>\^QiX,5moioU0 +qTMU9YO7mVE'JpZ2Y9lh?.d-7Q:&mE:Pm8/gQQqF:h>;Tr>G\`/d +sHVeTLXq,r^qH$/d!4FN:b0LqMqsWYno-qcN.D\D'LepI_90MUl9dqY[Np>+p]c0 +o)UM'\1CE9(gQ-Gbs^j[&M:R>8ll2#7KGXPqCXtGfVH41ds_+9,/fk[KN.;b' +l,[;)=[1"F'Veu`5jIUA?X[;nCQGM@Lj<'eV4H\OUO/6$Em8a]:Yt^kqq:c,l!,s +uZGjEX0:2h/heQ7*LQ4#;""m5Itj+\]n4NNduLFese%T+jV +/6OVdZ7:LW?j$[9*,]_%/:&e0aEB6Xb>P1dtR-TsIlA?"+Y"gd<=)qsaVT;1.>hp +#c6i%VR*7,msLRP2eU2lu%o9:5.ub!_W(Yqlq*JWL6OSjDq2#Et.\#&<8$Zg(@jR +;H>gdS]_MH!OroLg@dtUlF-A[KQ:ai8U_=q7kVPgdub""sB'8@Yp/5]11hg)s/aD +&-i3#i/u)AN+YNXGS&ib&S1-EYK +3bSr-XAmEB5e%0T`jYU#Pd,^^=VAl,93S/,KK+QK8CirYfp#DtTg(Wj7CFck6W>Q +M25aDmE/gVI9Di8Xt-`h`DRbpREm(Oj*-o6ON,c8=PB-Y.m%dQ9F2"tM2k"3/0qA +p08GEX#PM)^n'%i342\[9af1bFN$:DIc:LNE9YGFC6PIRffE*Ok6/!d],_>ri33X +[&\=eAh&26'r,($(_1N(8AXM5O5aU>CeprlY*Eu9Oh#L>b`*BWY9+mKN(6"kKm]j +IBd#GWJ+)om1jkP[[s+iup.OLs6ct>*j(>*VKdC?Cb@gBQet[&H@?+!YK&Y>>N5n +)e#*Bb*#\:`on4j>K[W'-)J@@^XV2"-\m7^3IL&cJZ;H3&eF.JtS6-%65)Zld-Fk +nC>B!*GO*QAsQ'$AiG=i""Y^^[+"38fFs5\TuA>H8-F^>:OiJkM.U#A$4iV#q1c6 +K$h4^]t*%kpT'g.pLIu.mBPCV2ne7;-^A,7<57EbBYX5rQGmM-_KKr*0I:4.Gs8G +jU+;ja3]Dmg8mSa#MY!)\s*l`_%(+3R7u]>\8i:CURlp>*Q&`X?>]*OkNu([[um( +gQ"G_TZtRe[9!BGHm".e/Ig@@#4/S2#iPiJ(n\(M7iJJ@M\B)`fnh(GHI&o&o8E1 +KQ2fC;J!6s3k[[oi7a)Q2R-C3,u'#A^1\'1H'=840;5L9ki3sgW;]\g.hi>(rIBIi +8fIHD\fH!\qq^L=%dL9B5#t-fMXJFW-LBJVKg/aN9$FlP4tdlG%nSQg"ibpiIK5& +lu\_$G18@^)CQkEfEI;Z>KYkG]7pY^80)Y1*h:b\L;R*,PBq"FpD\/t1q-:NUgO` +@Y`,4K8I(D7f!KQMgY7/(g$+i)0%#ig8*(Fck5_PRK]@]9ldsT9m@'hI`7hi7_`G +BA(:n%rAK="d6S*d!+G8:p#H!a]ja!h?p@k&CV3V&\)[Y8.oTADs.36-lCB_W`\_ +hU\0:@tp,:+=lmSC8NXS*jmb-JbO9X%mMZ'H`"gO;mee-7)+'?54Vm23kfVR4cng +ZV>8afR%Ig-k\%OIZ7iJ]Bp"<:]:?2HH"@!+T8CjgkBkM1j>_TtiW-ad'sm,\Q=c +Th^hZ/,6d/?T-]S"fQ0'WhlM2>,Ck[XK8EeHU2Y;4Cl3g!6Os8FiSeHg(_'Gm$R' +:95K-8]\+#j"7JjtKlTeHPiVbq`X+N$(>pG=V22_Cc6>"Gr28tBh_-rOmc0@JPs2 +1Ef]oekYJ`+agH[Z<:C7BQ!RF%,,G%IK2q&XCPifMbG1H<$i0)Q=8,*PhNe?[Zg; +eCiSD3Gm@1g2[.-Nr=1@H(\iCG3JT`bek;G0Zr;(O@X/IG%eWJ_^o"3Zi4"#>;bP +Cp@>\fUUBe>0TOZU2:9[k&R\;=3$^!.qAaQ_sk8`d1SV))[2TNO5a%7(@@CL%L<, +7udj?G93N6!$$-`.J#m#f%[%i7o.FfEaj?g0(%Js9r=O6Q>[*4(ki]$N"DtS7Sl) +-!0P=*0+m&hMA>`X>C_5pnh6@l^71O[L+XL2Z3CR%`]RVfaWZ>L +"@?TW_f#<3T4)=,U?Co92(*>_V-!Zh"K8K@3,G;'/V*_,4\$m*&ZSL1+K)rG51UN +USDIRCVP4I6g!]-=l#8JF8.Vb3'V(upf&@&0A?)d9 +S:.ifoq"J^rY]I9g3cGA<0Ub:87HcJo-\,=!gjSM*2_L02 +Jk:!>a8M9NE37%)dYGBRlCDpBqDRkL$rP=4Dd=hZIk#&NU0oV6deSfLH)*G>7'G0 +FE,j0a(E\KS!*I5XFSB7\SQHo`tg*L^DjmK9]6%acp1)945pHZjBq.ht/<.de(X` +X4$XmEcKgImT9QBhuXgKt]D@t7:_pDSJ54,u4^TnI09)!#(pH@]62,6$eqBb@+n" +aO33!.(O/P#'62k6I#CCANU0Hrk$)I:Tf#"8dp"Y^)fo\2Z%5Lc^G9n^lE^P31E^ +.;hPZ7r3Wu:h5GQaSC*^;Rk$qKD6$[;JpZBmZZt?CKXrTpAY,C$UUu8UNX*Y>/=a +QE(BA@q9'D@",2h)GRR:5M_1!IsL0'#g/Bn3'@c262Z%0Q9lmL_DlI;kp$JcYei+3q(d0;OE8E,/p +KD;;=*6l.X"O)f?WdMQV2)l=C8S%S(R'\,=l4INXQ;@(?&7e@g&!_a?TtI_=OV%IsZ7H$jRcPSG""`=fjjLfdVpKJrNQF>U,U\X"M7\k7MD($2TXDqAL,i5i]0 +J;FX=bA%%3$7#RnPsI((k%t#V0+m&3K9IJq'5[$@N8ouT#\Q[o0gsFrb_SJ3)iq. +/8T79#l-t9Ok1g@#AU@37<'$MKO2aiYKXjBKXkG[_QHK&+,%_G0m,S;UL%N+*AUAMsG1XL*qOq&`?^B,!KLKs=2_UI:F^d,(E$Y^XhB`?HOcQfS1&dY8b>NO[p5C&k=j +:FJ*#--Nb#q_s9k&YBV]GQO:L.O'Z7c">)60Ld.Vfb`iG#?rcfDYs2;&IK=N/S_e;jHN/.M20^KXHYFKLRj^Ldhko\'*^i"4VH6C$c_+,0Uh +f)+9'GN"m38jhkTi@>3$*_mVN>?d#pBr>=G\7c+f1bQiW&JkfMm&Y=>k'Wi.a3[L +Nchk-1i\**o?HXnadZa#59bV=l#4*\je^DP:'UGU)[.h]jEAdfJjmb.om&_eNmo8 +dXP=&bDR[p`;[2b(PEK]&@?jICaF`_J=YUsh]8rqbhg-o)*<7L8#laNnjh1/:=rj +% +[\@-NnTDL.6`?BnC@A.bTBb/`\f$naU_^R+-;6Ks3_G4ZaRK#CG4geUPA9 +mr%T&go0XC%,g2ab4PDj]k(IXN8qB7>&qh/LrN$M:J?*55G.7EG=MYkG9h0*(c]h +/2Y-kJ5@(DGmUno>IqKsHia>=8g>I8fhUf?jc9JYi6iR,mY,6mpci27"X;D+@o-; +=,N08Wf%Rr-s3TK>gH%k'lG40OFl.t`D\nti0ed?6idR8\?P)ZY># +^cjXeN<2rr=^=L%=qtH,tf3n^q?1em]g(LKCYc5dL/6$S/Ie87+b;5Y)49RhL&L"PT#[a4j7LIOZ.*6I][8:'AKENZXb&<" +is-IuJ+gZ"ZYn]fL8C^0T'/0'1&[X'jcZf=r?_gZZDS:?'De@L?PQNAeB +&8.Z6OUH8Yk*^3ss35W3R*@jJ$Lk=JV6&5`dRaj_:&6u795l_WFB9jB$!6M6a7R^ +Z9cL@dBOIqrq^-DZ.a,a07a#B/X&g6Z*h*S..OHR."(!09Jb'n/>,EChbcE(Ln8m +acsfB;`hIWA8CPdX$%ejpS1fe+#:7P#cs_3,paS +=`@m'A)3A3j;]4oE\]A>o:.EqkeF9s;P\,m\kdP'[F<65pE"H*]Q0!8Y]5V-dVi4 +?[F<6I:,sBTG[;9[e1D2dpo)jiq53Cq!Pc*\Y+1au? +WhVW60[i,1[8DJi*I7^t8,9.f7r_,OHik07BKX+Rl41,C,.aW#LJOB6DT/_MK*4( +#=#IA5Wf$"Q56Otm>?*$0*bq2XH"k9TK!;G3<:Y.JIf^Ae2"IJ\>#Db[h!gG))Tq +dfRNp1.6A]V09T#6=-OqjW*t1*-L'q9A"oD0$M]!mK&poEPVA&dTW=>I`Sm1'eLH +^%7%M\+5FY(oqOS)fiI7bYR[kClEbV.s"PB256qC\s$@Q>e;OX7,(M)9"1+Ins0E +Oj,Lm#*N;P.P5bMH_mbuYAd(9nHT@mj/!?"Z&jroWs@^H\d4bPR3AoUoA7A7S5*Q&dM)4&DN"]ug'H!Z*3VC"e-;hHaf&P#fu\C1 +\Khs^c"h/ALm!=>9*AqGJ5d/-?j>RT((4@dS'N;8lH\O+'dK152\81"H!&L%ODRq +N8)L<72d8VMdJLo)_7#Sa!$e[j0f99".'inb2*!Dl[F\fYL. +-_b@!-(dkiS3VUOsU)p>jfTNk]\8n-jF!A+pD$E%jg'IX3jX%fD1V+e4/=rriiZB +^Qoq`+b1!%Ajt*.)cJHW\d?3HTTi[,+-57#HRf@Zi^*j,h39>uarfEV#B[a)%8A[ +FjekUiW%&WNG6@@n^#ALZ-*5rHe!u5IDWuN_ShN] +Ejam0]:VM+V$VO\7%r(aG(2uneY`m7e,=s38=HgkfJWb:@%oH//Qfe +qQEFd1sHXW_KkR%?A$TFgG_p@)8M\ork,^ofV*Bd?\F8StE2T[$;YO4Q6u)\".7: +Qk6):[I8-1E;:Y9?1iEqirV<3]8h4.MTq:(EK8l>oA8d,[K^R\FGY4__C=@/jG] +`S",0KAq1/P85ihR;(O*%lmus^Fa%s$TeF&(J32(_i&6mCn36,D3?F6D$;Kdu[mZ +[&")!UWZ\RKt"jY(MSFNHAO)(/;j_bJrF:F):`"!-1f1"/.^6ucp;6Z[Wc]Y4XpH +arFcb2XeQLt%NsmF.q(4I`ToFL7>AT +Nfg@jCXrF0Ik3m$u45LiHGniNi/*h8\O[C(?19JJ%TWEoL6f2>6grg:UdjhUli?J +XjT.E3-L +2R0I>A@%bWk1m$/N`Rig,a>E+o("e?AIC3?W$S)Z@5Y/l%g +i!jfIdbMmirG)YNP#boV/D-f?Agd"qg3Z]ElchsgoplB_PYl[QKJA>7#G1d($F(a +Xs7s3`84+d'@?ZWV^14d)1LQVBt_Wo-Rq]1sWG0t3\#OW5^"$%JHBfY7)!@47gY/M^+je? +$4g9S^i;./VPEX2L%jiIX52];M5W3,/cBiYEtigp66R?8]#/0\s;6_csUP[*10Ye9j-8EWYp9%cB(+jg)a +#kgEX.*g+Y,$en,!p62`;u?f1UQ0^!.&kSOuqd6L#]YI\74hR/?`opYj8ZO4-&IF +3'@.S!s7a+4n?B9NdI^r2Htp*C:R:;7">iZDP9SLN)o^9:Xs4"XEKNjdqs8D9>.` +]/52h_XCCrSlGcOB2HrnbOle)>93c?RL-B_s4;H.:GU2h(C`A;bmNhZt[]i*bd6Z +oleh1+\F4$LSN?!(?g=KVW217P3o]pq,.W4cC2O3E,25I\kb +01`[*bK?r#L2/G7X_f@-GpdT,E8rP!kTBtM\"gg^rN,/qYO4lC"!CJP3+9iP`BmP +:ucLS!2nXN8E^&qW1$@6'A1-G^1.t@0H7K3B-C"V,)Q:?&M7nph.PR" +o&kL1.r\DABdA.@Y;fIs5B@9oeVMiVtMC@j;&O[=$c3MKMSo@H`J]AutrG&YX\Kuu#[Z(?= +8Gc%jA.?>Q>W+U_5F!ZT4/S=7g0OXT1qoG^kTR5mU92#>EB"q.(u2qklB")Nlp0W +YeThRS4J\ODOEG#_OE(jk^`4Dd8Ej/$OlB378D`?%\;]/C^_t/qj1g&NST-lUWfJ +lc'i-R&#!fsH.EUTfc7u^*2!Iq])Wb:o?N1"XDpto2)mGJ+.f#ZOU:(7ulsn058L +$4X"/5JOX+Cag@n@4AlnEbK^TN'XE,"j`E +8[<*a_e%6OcOLS?e26!h:s('q=`Q9gMWTd"j5W^<0 +*PY?cJIqj,4"32HH;ptPEJ.&+5e.&)S!o:LtfCiai1gK+\)T22sn*<8'Z65>`:_h +-W'!0BJ(!lT@P;Dl_+B?HFaN/%]B^bTIs,l[l%6\%c+9mmW5D(#4)_]#,4&dNcaB +9#2=AH[Z,N-I>"@,q`TA92*6BidrHO`)l;85^9\.G]M?!!#:cZ;1g%G=%IpLYHUF +p:fFDp\A0/FDEoPUJZ-bf?!:U20ish]#>T`:BL^'4pqA&5r\j&"p[0P^=Bi3WAN! +fno0HV,<7U)B"*hs>(>(^qaO&<4loT(3(E[QPa+Mjggjte$pa#rN0./5FgMfVCML/tllFJE7 +Zd*M-\C)B#&lO%O?"1O*P/Ueg,OQ1B,BuF&*8LG"9gl5+ktHKAO4-^0eM?9'qP-. +SRmM-3/iJ@BR]g9A2rLY7WXNk=]W5W`Ao3PmJ,F_g&D%RHg.gm&kV+f=Y1k4D5C^ +iUnsAW%WWD)49`jL*"Y/@BNDYX*aQ_4M.L*JdUQn3W<4#Ej!,EZ`u2ZL`r#ubBG:>qdc*Y*p59ll_WK_>g-@D(.D%\a\l +8%W"ChQjBj5pkmsT?Mr;2FCT%ciLRc +Vj7\[O1;#Z.PFFka!RBUg=F@TJuB'_A%`1tJJ_c=K:X$42QH6M>l-DRkj?uMqX4+ +FUI%ZicCZ"hN`K_53XqN?ks\b$3+"N.bh.+W1#V+ZUZrONNE"2> +jK*QQKjeGm&>7dm>,qPoQqm(iZQ1_3oa^_f:@2d['lZIHbONHhH:#<+heofYF4Z6,D6RfUS?TQ6!F5V:"6YX^mKLi+kn6#dp +^6HpJ*8o8+!1.hdr>A=haO;XeqmYi,rn&rrtGOjn[P$M-b-Ftg]1o5&$)gGCCX=k +ss][pj=fm<1rG0"uPamJQ9?#o(0Ti0UW)CtqtO)]-$QBZ@G]4Po[E#*&@:+K&h?b?c`rd\/A."pff&?;CY/ZO!bN7[qp.<>r& +H1r+.-%@J]:AT>6t==r.4*O3D`_-/mp:k8d>XoAF)Q=TG1,4(gfbs)5qTLPb-\5d +G4@[S7Kn9q7kK[@JPp2CN*#aeelOe.C$*f*[%>EOaTmS73#f0)3&r?(cWnY1rf_` +t2!`C5k!iKbPfEe`.\(=!;Z$r`V->$`n8M]<(c;Dp2OP>S3phs__$"O9.tbGh8Dk +% +N4:G_D6cl?lVe8`bHkT_jf[\%0#/ic?EKgGk;(RM`\t^]X/ITTV$lf/X]&N"T0[PaZ@OY +-Le"T"TGbpB6H0bDe_mZn^2[Of\@V.m-a8.jALD2[]=C5i^IbJSm<(-gaapg2sce +*3!U.H&<@T!1eoJJ4\sMm!5SmnHYD)!*^t>Z]PVPT4GM(']k'-#Y=4c2^/]/k!refG*hY/"!)QQ; +*a0N3Bp^1P)SIdjnC$ej3!.]C0GM/qoeA%b>.He>[54=^h&m]#N]"7ju^1>ZrkK\ +b-IWkQ;g#S>-+@.[]-2EYh@.>+S%^njS&,s0t +E%alLn;GI_e5>)8gjE-#aE(M"u&B(r]'^FZ%JE!&h^Rf5<>+1hV$]@lI22FeVlS) +uYc_\Pp9&rrCu&"cC^HVWu_]'>V(2`5-i5\B?W]*,ZAu_6A!EaTjup2u>[-(TVI% +L+VCdG!qbW\(\b%GQG8nJ58l8j-nD3qo2aHkk@B75`?tO+-pU5*!=PD6qJ44q)I;Sc=j`;[.l1PmI`%lfk)e_9-YmFNpO:V1@@.M3'C +% +pFbIcrTBt.lAelg(LN-3]r;=;_6%B9e#'!W'LA&aLO%Zmbq[c(&$qqsO3QN\O0QM +ERkFBtYKUP]gFfq9@Xm'ua0H-:dGEXl7g;InJlpaNVNKb(2ADiueh +DbU^:CW[hIMdpgV"9Jrm!S>b_E)0&.G2MENV#GZEUj&.Hu.#\R-hp_2-*KTno>Vm:&]G0m#*E:FTX1/@8Lo9+,h%m9a=JYnkJ*h@:\'#(CrV,ki)bGg.3HZ`,OMi!l0/%9fFSCa1&2CgK' +bKo[C;k?fAJc_o4Cc=A'@IKX!(^2[<@+!i']SlkoQ'c$-Wtrr?aBk33I_.RI^*>e +77eN(Ga_j:6g4i+)l(j,MT!ZlUqnV4.D;iT?.d&;_`E4CaKuH=RF(!\ao!FaA_LB +eQ*!\sc%WH%p"h@#>.J.]4b9cRM$Nc$^@I5AaG\BW$,ECn:%[S5[m20@nmFe'U!S +Sp#6j<8L$olfL;9&11..[j2O*N-qP&ldD`kpJA\!Xg+mjQ8u$=a#8#:/45@+]\r> +J.VN`PDW$5CeE2m%rUWba$H!)uj=!mAj`i!Mqpo`$7p./;e%U?#TroR90/9dBg%g +nh?5pEW,6SEfa/)+s\r:IWGdhR_b20=;m<-r(7a[skS!5HVAX5KZ_D#JYA/r'("s +2H6EK5*?'X2doZ/9Yd&uWrd<89NiE%j8f$(Q[1H.,=X;'EaOqEn,k"X\HAf2r42P(-RNL +R,A]qkNS\'"Ali"r#fqL`n]r>/mHG=Jgo;Q'h-.WGKI@0_:LgbqaiPC[Nh"OO2$l +I-VapK%\#$LaD(j\XaCVq9'WeO.A7BaY37naXi"4R(!M"W^=oidk$<:Hr0,`Rh!+ +EG>S;s6S^r8@m5MAc:,dP@inOBd6E-T3/S7gRo_<]g>]B-RHhBn^7WaVH,^s5_AP +LuBH:FDu:KOl6Jfin>]kH9`GOmK8eJA][J=Us%Fh38Z1`WcsO)9u#q`i79?\\ge@ +T9(j>PNkF"1[F;RT0N0A2QGQP#Q^?tUYgXEj.>&detJLo*$)dDN%`BK:J:eJp8W+ +0C?k8^lFuDgHTT2[[()!RE(ZH*:YopYa/(!\MD(VH.,M>:ofM$`;]odjLm,YuG^lgg0>5AlEMr +86,7L&R:C8/HRM66\=Mk%GmXs*Q0QEA1ldc)8SC,jPXO5>au/PSTR4jE`^Z +elW*n/R,TL88lK"/B:3M.A$M%=\WAS%5b!\)i:5EZ]Q9/hSq_rQ`4AF9't`03DX[ +/(\WH5rVk(G[Gg9CF4Q'2Mc1dF#gKPA#\I425b'E7JI\SmDbVr@peZ?K1Gn=DYfR +UV?N^(0;*-LS+n->#?@HI/A9e/roqVBlW\*)sN$">,L!i]8P'cV2ZB72(:euHp.i +FB9U8-JG'hH60-36PfOccf@;$_.aqkI""Cj"O04Z'ICh<]0[k2IV]i>6KYrg^\A8 +!sG=Y1c[4_[.8+:QL`EgP29*2@5Ws+ +WSo]kKDu^r].Z]ieen_&[][&q]LK#b7C._-o:?et0q/e5\&SpN3/E!,NjtA&j<,M +\R3.1\c4,CpR:I5n`&ZfOZ2KuC+>XZ_D=k0>M<'],.*.5s2,WAYV5Jl'L0nq-!rr +BE!0U3J!?@8Lni,!cL@JXINa;Dg2X-$XALbs>F34Vq(*RluLmW"5^#>hqG(cYDb3 +QUI:PrntoCAiI)4"m)b/u?b-EtQ"h51W_+ZN,5e]W!"eSY:?0E^6SkL%1IN +P2=da:6ILE"uaO,hn+Uh,i!Y*TED@^N*Y5MXRO75d3D8h7hhG[PpA!53*k3B'fZ2 +Wo6e;2GZ_?MCU%XK=u7#c.tfT$>N6uI!!3:>H!hKq$b5QY=e.NXoY:;G/Q:DBp]/ +K@Hjl>3bG?/YI@hn\IHn%n*"YY=5q4V[K,YZJM]l][:!@.\b$JMhr<]%U +/tJ8Jt"J,m*\M!&lc=lI+t^G3XBJStR\B?JafHjY/\6[Y?*&I!sE_Jl8o>"gq`XS`"#+ +cH"7`m^1bVuOt`s=Uf[+n"HLN-[p,)*)2e"6&fdcuGol$Sk@:_@B\H8)E#9q&"cV +fOW*-71pXtBt5ul(C5UD2WRopGHSPtoLq^XH>g@IWuS"L5&0WMa(8,#a6KN +1O4RSqAS5#qQ)@MDNH7g+o?Ur@a#9]\eaG;q(h0GTrkBb!U.F,8go$u)>H +^UC\\ZaQ'AQLJ,rX^-\e+\7H^lgl.0IGPbsP%lGQeX'LorDSbPNAeC^"PSRVrm9- +]Y:MOoo>\pcZ'%HW9Z%8YTa0$Tat]E<0QBG)mn&ZU4==0qhV../F$Y.)g<0A?73d +u*."X`883T[I]_Q/#nQ>!@lPJ>DA,.uKL:X^]I,4k +-`./<0P%@/&'I(aI4;<>Z79+1rI;Gi3/4;mPIYVqUN$hq>@#lE.5U0@Y+?NKPe0r +)Gn4:>Tf,gk[)8'.bgM8Af9l])mFYK@_kc_l2@mJ^PlHZ&MXHhesuW!.k;3Pp']] +% +RU<6NcS!%=&?E6\t;`L`r?%]OG$WEBO($u7oG+QKB6>Oc:L)Y<^cenLMed*MVqan +lPD:10Z3UB8"Ho8]?#pq+KCdKTZ1\EV(QP^?JUcm2edD%B:opcI;gZgO +?bRZ0,q`N=`C`r:lM&J+1(E5hijRPQr=nQ^<&+isK]6Q^lM>["*Gg!PU&L46ialn +$7=`N.ugbH3:f<$\D>A0VjmElCM"e?ne7skR8a?3E8l'G4>D'#IGg3A/MZCAXlXK +a1q<%BI>_k4WW4`eq$$BuP/kH@;(ZsBjf>JgKUg@2!m".5?rnG[=!c6`m#Ab4#X(2kDNe&4]Oc\3>/b#;W)kN_VU82:_Y[IbSub^1&dWm(-HJ[CF%iY2"*IN:oA7E2_Pt34.H?! +#*+QRVU1J!0HTt7+ZNs. +e;+pW(:EcJq@$KiNA3NDck*OL$qhFjX.p2e'B-1'\?4+RjNCdHOIF4Bi\$u((fOf +8%6FkcorX?Ypso\b,@^n(Pn:hQSZ()Un[D$JE(Sl$&Z8>$Bek8EFfVaVm.<79N)6ZTM#CNh>\rrD>XNLaQa-s +r6ALr[[78s]3@CKVp)N?M2s-'Ch+4H,UP#3-eN8^;VM8p7#c^)O +2h9/s!=QFC),m_a+j/aeY(i^iOA%&esp>DXS*@K^EHDib%2,H0k!C@Dr1Kon4c)V@^roW+BteJ"=upZ(f +N(c#$Z,H52/Ro3U0'PN2Yj0(g&h`=NP!3qhZc">CEdOOP6pJYdO-)4d` +/K33aA50MgAMQnq&"Lq/b.D+jf_K^N4QA$8ccr(sL3-'7#n"^dR8EV]UQ9mFL=-C +oe.6FHEu8"*GjM36+Z:Z2pfunLT9oWMltS9mAD9M.>Rf-($"YK +B\tlHYGM32W*6`PLn'mhY5b'CN@M4S9uimHe"os5eP7eXloGYLc,YtV>>9=N:Fl1gXkL*uWt06 +Y`.2BNq":CL[^Nm#TM)8\Nn?(#?7o6fJH5Tl4KE`\RtJ0mkE&,U'Zd%O@ +7ZWf<)B7"Q>@(0E_6!fe*G>X"UM'0L02)VYncG*?YS:DU5H:I.&)S!.LX?@35Bme!&aln@BQ?!BB@7`\GeH-"8;#DO4?_85&eb$a$DP\'jp0( +/@4\nb$'>Mf3Z?#-R'-S<"H/1d.)o^bjbaaM4&fNg:NhO@&F55%>s@R&1Dp#)9B5 +-8n%1tGid-7BE\\E=3$0-6m\W50Om/do"+,6M_V.2'SZ.a,V88B:p[F?GV(W@50d +["]GdP/Ilq,`Tt^mIM=Yncj0,5UWEp>(iHC(MRZ_:J\ZRQF\/2J]1NaV+SC=$!R; +XT'PIjdMpr/T5C_FJ0fokh%]183)I./ +13V^? +-0+W6E&8mtk\G2628VKlX-2#U/uTM;QcptA:X/^?/aE$Ptp=!6QQ3IKti9-dA)3! +SP>=33B/YbL*Ifs#ZEk66bt);_nc\.Z:*([UI/2P2;3@Ngl-.C)[RI*/:BA%)PR+ +QIb'c3;KubI?@%l`L0e$%.8E5piFM;Yo!:]XHN=RNa[R\_=2b,S;.M&Fq']$?17. +[S;$_BXXeWr7-Xo45LjM0=]sLO8He?*0e5Y%-&(/mMN*=-KdnjUm#U*1eaFX>b!S +_XAe4Yaat#h@C`:Y2:T#bRP-^>BGLHE*J(<3*[19,t^bX\#,]\#A_ +(3deCHCFX^Nth50]@L)G)gNWTj$Gf7$A2f<4rNRn]NN&,;r'Cth9XOe8#aVJq4NP +kbrb>aQr&jGds%cF1mA./H"J3hm_'2PL.W3]2C>MVcl!kXeU-7fI&"QH$?%RQUF`)=q0ka@,[thbD>%;cl:t=tP?Rdcah-H*f(XMCC^F2r +X_,7^H[FL?4.C@hmm!2],]\E)kgO8"I2Fpg-_@,ln\"DGUYU05<76Fn&i$7hXHCL +1B7H/)"!,TW*a'?%1g)gMP2*%;jM-ZN"qjX +T'Dj,S?WmT3YsrnVFfVd&cKCAuhS6F!/.#+['ZjS/?`f/#tb*&<"P9-Yl_O.>gS@ +'0dh%Ls#En)ChUd8ni*bA6/mW(H$u*`c;^=,lA\,kJJ_!,pqV0MLd6XEr*OF*4+] +Y+l&nI&H,F@:NffYHd?C=-HdD;,Rc0VVC^`Ap=>:49XC9@iXq0XIWM5V11)apGWh +(XS_]3N6=@(cP1F+FFb9cj,I84BN[XV0nt(0b7[8K5sDiX;Z/H62KAME_j8IZ'el +bu^kY%3^39fBX&)p9VlJQ+L@!L]>_O)@N3]E)HZP#5ggGI,EGFTI(DE.IBHijAA! +SeLLkZ"GhH?^bh(='\!1n)U>&I4q^V@\e3Om,A;bbP#TE]\2GV7 +Z@'Y$h].Ff1CkVh@H5uq`&,I\DTo2AETUJT%-c +&V_;[0P(1X@]"MC>]3/9TA/jfG:MHRpFW9(,R_iu!D8j[\nAq29Zu,E&aCqJ7F0fj(#J!ZO:,A):<2cqB;Ji8=W`j)F\neJ&g +U=1tFsg>@V.8X>Q*:8XXRh`;i:K]Nj4?KNBpSp%>Bmf;Co!IoAIfFua>,df`2=L> +h"juj6$X\#=5&pc>R`tESi/u9Iju1ujT(@ +SFu53*"4(f\ek;3p,hJ2VD*KPcHX2+1HSCI#8U'tal*`\/]BiRfb[].mH$DGok<@ +P[/`OKqQ"5K`5oC9R,XJ0Z&Hct[L;jK9!9!Cr'inOu*A,jjioWekQhR9BG>=;&X> +0J%39>08a3&gUN8E7B(eq(mXkE:O9nm:Z\79Mk+^'%,3?t&Sk-j?M,hFQuqnJZ3Y +MD:LAbQPq][n'a1Bk(n)e9&fOO721Qs/V@srCf>\J/t-RMt;`;oKO@'r6&86#gB(*'B +D,V<5lt#2njl5u9g0!9u6f:C3Gmo]rXNK.C1UQ;]"G=TB9V";0+8PPdc_-]3S$H6 +fddI3l`\XQf9X*]FeeY+Qh:&:8I +13,J=Yk!U;RQCEqb9#QT;KUdrSbEHAOLf\jWMS.ZTJWX]9VDlnB?4WIHn39J<1'^ +>P1O_;!PLah@;Q`/k?umhKn_=eB7=<87_`#8dcR>]=10a`uB7S36r_-I\9c.7/Ja +_GCG,k:]X)WOcFGf3Sg3T[=_gH*_pX%2_R=C>AEQ^f(iS'L`'7JFkt>PFV2XpN$3 +Xr*TWAc$t,46k6I^e$\VK)@CM416E&rWJ^f9-OjaGpH\s`rN`b7`NB'iecKrBn!s +/7YSa]?C?#u<'-$EkW_$UH4GQp,0,P+fd_q")" +*H[F2Ie=o^s5D'\01G-IEb,-@C4&6-l=Aq,6Jbg(QH+Sk;hOo,dK.)o)P7B.]HrG +f:6?U*D"KZ$EZ.Flae\&J0eLM#Hut"a/1l;DR:b@[J@MKXei.sQFkPt4!5C;,%DO +EJg]MS"s&_L4Ee_-qTrr>:H'pUnn7aMI\9g +#>;\E*W(SD34o7]ZW&g&UD0U(I'ihO^0YlRO8uGI$cX9tN"!Cb:YFlGh)%cK5JE^ +`L86nZSg=&U7aVm65B%l5#7]V%MH4$t:7flt<(5@j@`/E7O-d$iC6@Xu4J;b]d0I +% +6`3".Y0l-+p9=5N^FfI%"%#!7E#s[6BK)'`tW8'&I&t8huF!J?="hMY?K6T;V%Qe@J!Dc#DNpi70"$!70"$!70#3mA4B' +caM&0kRN/j +ToJIJV8#kTu-R=!5F"\9ki%Rpu<\K(mHI\oRU9?7=A%ArHTN-,5.PHM.`3O\,iGcH-= +WuXL'k(Y=`R(7Z8ikK!uiuMK.LF+07=c*-'ZH8q$_s5PIHf>A7P[8GoU\PM/,5Gk +jIt3=62aT9FfbT*hWP*K7UufY.LWH1]AikT;9J+_WV]?l^%B#%4oG,&YLCfb['Ol'i5Be[a)"^HYXi;<:=;c$ahj% +;!iC6*!'-rnYuol6#p[FC1_IahUjs-_8d*GeJ.>C`OKI_;_R%"_MC#lMl-W+r(DF ++PWOUqH39U]'h"a/p_\0tr-'=-f,$:r/SRER[">"2HCL@kWPm-p?I/IUp-]^h_Dg +j:Mp"*QbpX\/LmEZ!53E),peXGaT^Mdf3QBE\60"uTL97*OX0)8cMf\TR2`q7.;( +P0L'h&Q/Ub$3Ml\i\UGNan=F,3R*e]DrfPmT(I=!!9GD/B4=E6`3TN2,3SBPe1%- +bWDR*^b4Pi.X*h>L&_ +c4W$3Q!@6\)433/%'^+AsBTr&oVX"J@;Oi]3.BiJ +]@=( +-9Kk6ZFAO3E#s9Zr$dVu2c+^.T2'.#]_aRgb7!Pd4LBoo`5Xsf_2pY6Q1G=G:RKc +tq\uE'q0FBp]=.G)CO[tkmP)&^d]IX-Za7BZSoo/h,0;^rWVMc/Z/-_g,k@kp)<. +&5e27C++P/HYBjq`*_$#SV4Rh:1iO7pZi:O'o,6$_JM'VsE\AKle8?F*YmZ_t=J] +ZscGTN`M2>eDj\'u"U2\&BAh2Gec#Wpq._:lqm3$8g)[&Q3e_c^^-:Y4S(FL@Uj< +[-$:JdXR"e8?qf$S-5296m@6OIQBj,8gen\`B7b,a6=ZnuX:ILj<18gI2dsZ[JQi +A+O`;G6qE^aNBX*LR_=Ep2"%SRqQ]HosIk'[,UVr"GDEN#kr>&lbOIZXB/&5rO.g +f!,'NBo)drP\$Jat5&;Zkh=GJ[]fFDTnSrdI<8H*]O%&VHHYL1[PHYgWU+EBFg?G +'.e[hM>o?hC-#kD]DY%?*6$YNT4gg[g"FUK00(#j# +:g!e4Mh^f2G1""NrUV +oXiO#@;K'T%0VQ.[,nkj!T&!T4r`pF;$L7QL*n@]oBBJ+cN4`P2!(*>i[5"MVr#e +_&SK*eJi?X`ogpPjbBBhgcOW4ZC3*lf.FXu3^5!p=8iAFl0OP6G.NCp\q4%V0M5P +/mjN2Va$G`_X1bC9M_oEh0s\RLP']IB-NJ9i%.$*hZk?Gtn5+)ZP)SBY2Kf2.CfMcP*BVCnN3>^HSZF84e!*g +t-Jg$,fCghG><:.R'eMbGU#LT>!Jmi+PTf +:__dusML@P)@#GEpb$3#"cJ=#D*"6o.14;0]A@7G>ZdJ76b=>\Pa_nAa(LSp_(3TO'#TOHo2qSU`Z +00qm94PU123jBIALhm[3Y5803d]n"Hr"#DK0a!bEX=5]COrO#HlYK`pCQBt-.:b2=+Q9#Ea4,+>"EZL>b5o+.5mHJ@*d"EU9&W'4q86hJ?t5/hW_tn8gj(P:R<]>f:E[ +]D$@4US*mN;T52"1V0tT"9<7!$=D%?qh%!/&.B:l*^=\:E#;/XX^mj6HFqs9ZP__ +QU,%F"Zco1sHN\&rMm_35gn>Xu;IkYESSWH`9_/G-J:c/da"BDK3KA7a_@NPGY:3 +9-o8Sh0Z&A6)%,&G:"]p_sKC):_0-'DCP9D/mCE+lZ3T./(F8:9m9M#7eSRe.S6n" +]A-8KlB`^i8,p,McL$Ck`DVV[<1FRO#1Y@i=_oL>pP];dZmU)u#m=UhU96 +IF]WO)\Bgl9;dWqt"10C%M"$%aW]fY2^_[Fd%>9-%PT$lIbgC;c!Y. ++IqOBkYTb(^cZEO=7,!IR&[p!$EGE:&K!;1Efm`ob*B0413QafhYE2#C!"b +q/3udb`Xb'T+W!?-HE$3t.=gi,fr?%-p6UAPF`p>3i<`Isp\W^Ma%cZ^+h;m.=4&it*tN(*l2#d3+\kZO>"7r(H^"F/?iV]HMCTs8<_&WWUoI# +3DXHl/MC>>e;+20!;+20!;+20!;+20!=-*8VpfuFq5D]4t#oCW8H"R]/g-&t4rr> +2F8+C^D2r=68/#*Q1SfV.ag$%$W^TY35[1cV*5I\:s$/Q&Gjbe:nfd(II=\.J&%j +M=Xl4;u[Z!TnZd_pW]^ofuG(ZPLSJ\.T$*gu8!e+!h)AY4om)O69G@B:Z7A_E$:3Dspi4,fc,)lms!d!0)S8?rt +m(0M.uJ/Ef^;?q#^*.gpG(b\Y@?d-UIQ5d8tk]Zr248'OLTcMgO!*73+0]#CT`,Y +qjR<[Q0*,ZVcXCXsur7\@?kJ'Nmm@d@HT[]_&dAM1s,5mg3-YQa67#duLi0%2m6, +DKgIY5VdWNGlho.E[n9-r>\LT`?GLaTi3;:rRM;`s&<=P/:[fj +[!r'prCXLAQp#Q>7.RNSsTTt9r_o+9I%0:Xi,'+XHKa;LiNtN;1oeMEXjh\VRjAT +p(<"g[[u!g`P0pDA;EbV)0l==*CCSaM6?\ng,3_OIjW^tRX]AN9':t1PtFg%,1iu +Ok*d5[mq05PcX,DX7b`WO8$W/a32)OEN_Cc9$^*i,\I,0Z*/[g%-IcY=%.N+)6J1')(*dU>Y+W=g4]3eeh6@X:1od@AI +)/s\;9hXU*n]Jj6L8u`[g10efKcu'D4-7R<(.1RS.KbWmodk8k1%8s_l5p6Fh!H& +dG@>4L#Au1#9?=4::0IMA%RcZaaFgq[sU8@6mR?a4>:#JjJ`6Yic6J?o%i."h6"* +!daQ``IjRbLh0lG//FG-$L=-/@ZB>iPBa/O(klt?O`^05Bo?B!HlYO!8RkCOjb<; +uEbBu"ZJA,MKW6Ws2-Ns)7.d\RVDt[t!Vs4hMpGL]Ze +5I9hH@t9\%PWG`"_^@Jh5s\mm2if1/!,Gn\(.OrT'R$OX0%#RoP4--Bd314Ng0QZBUD\l?:a4QclLPJ\K3g_56:>r]0N27hE$J?`Q%;Z`i<)io^C +@uRY:,RWRGaK-O#p4_"ZgZ:u>O5(,&\Y!L&]Zs=_)i&VY1OW-o"5.Xua+3K0/nG2SZ2Y=o@7* +-A1m?;G8s$b^T4OpQa%&S-iC``7Q7%pT_2:RYK\VKm$TT'c(N/Zmt4Gi7V,"/TAT +j%6p:T$jr\rr=D-?Tj#8/R@5VVah@98[H$Vf.Z6:l'>9u3oc`RlVG0[b>17V/-pd +hIbf[K#41rtoHLRd/<';2\u"u=*s6U+EhPHP/6ADRG2nIBY:c][#0L.#M/ksT\:b ++9"$O?^9+I:6Q*kqIFedXU*`])g^R%3r-,Nn\d>*V-k%L,AOJ._CaM;&9jP]2(&] +_/Vo.$gc3A$u8Kif3\PtaO34N9N)&F)2]rmop)f&b +f_ST^VtDFhV]V&'+2kS#[.Jj?VVaO=M'eXI-*eJ]L["ToVq9@rbrHX^F4W7!95q^ +V7W$0Gp*:(,-b]aXQ>p,%k2&Wea#;KgmDdE.O#Z1tCH@aF68i[d?U_$kCB":W:ID +T!QWM+/8Qm^Bbk+Qkpm!&3\@dtY16KZ47"fR,SiqPeY=n@D_^W5aE1)`5D)GI,QL +W>a:`hc/,[d.A"HF993T(oBLYiKBp%[nH4]X:OU'VlSU'.RL.Xpdi#/h[G5Bqb!1 +)dk"#U6^/3$=&%L*[-GEMul+!rr<\!"RQ$=]OThe$o'Pg\mtX7IJp^<-PEE(BmO^ +_oJ?eH+oVKW;PE%o1Z3\kk]a^@P"n@AB](hAO/i38i:_hZ,k1+H.9p*eQKL%fH4TeSrs4hcoHtRb.&oXgZurBU# +ZBa`c.Qfj!CSr[ +Jp6-r:JfN=OIp1#q80npKAJVg*O[lA2!i(\<1bT2I#8F*0.QW":nfee&D!>ghM`1 +Nl]WK1;*;+CuA]`l0^%$?7T8ufc/-MZLQ!Np4bP(h!tYi5gQQ7>Kt8$8OLJZ-n?i +"lnOHF($V6sH@tHe;p/nH?7Ekh?iCQ8!%[jdeNP+p.UL,sV]/gf92A>ZR;P5&:(C +ie2B,kS-$"7N4Q(A.f@ucklZQ&,;$RkW,5ctDjWOrcMuob"@,j6,Z)ibZ[uq04D) +&h+$Rh3YaX:l4$0/3Kirc!NQI6Qe[e!;?:kH1Zhr_s#j$/N6l!j/1EG7utPPnS?H +g6eU4f1l2plq`#bMJ?Y6bJ@:Q';C[FBj>#:(J0S6SW2b=";X;APLOVbB1S<%%c?O[-=bAQ>kH +\[*Y#ID<-CC0=fl3JEtO\+%kgY2E$e87E$kNI4jm"Fjo/>n2[(33N0SJ=O-5CoiJ +HLI+M;j\[Ykb-\t,uW_!Vpq#uB:(cVa^^2B\n*Vr^kF_f`IWAN*o5J%Q<[MujTGEX=!O"?.Qe3dV4E*TSR:aT^848`$odll9tbJ +A)iKV]M5kEQ$hsXJDrH[]e*CV7+.Vl[QT;gtZL<8:ceD;H +k&E[Q6,u+qh^G.7o*!,u9gLG1j'&1(Y*S>_+g$j(01\,VSOiPnWPj-BJ92;qnh5$ +>)UASoS(Ddm#\NH%#qTQ4b-Dt\FR;#,!0DB\l[g\=*44/5Ul7r_ZW88i=$5q^W6A +GgCfGejWj0,?pQM4^*P#RTBKRa\;p2.V4O:OPNW(`Q;8GCGJaBRf[!<`qPrr6L9E"t9n\*V?m4EHcMJ,9$8FB8buXG"-,)b +FRR_)uAl5Q-)8=rVF9[=YkH=*N9q_A!n5c$VUU3rY:[\ +YhT+j8sLDC)/juM?WYDM!"V_Vfk`dF<&7iONpK;nFqiu-]=%gjna#G.L!jLqm35W +#Hu8G-Kd,iAj.'M*H?@CFcGCnXaFnWFq#fs(XOD4m>cQ-38TYKc9I4W_TfMkJU?> +B66#"jqe'4ps2W"#>:j,;'mcIk-(hVW":Qe_E^BCu0OS[IIh)!1u=]-%riP7"^eT +p2i:k"Zuh!^IrC_/VM0Q!;il]oTj#C5/0(1a3TJIu]5tVS)O5M=1.acPrLMK +JNNUh!he%#ho%[h#-VBo"qUsWlfmVjCd#p3VOpJnEaoNQs`E&/\7"t-BO&NNXqi9;:0X%p +kk=at`)!*CXU!D,K3ID<& +!P2?Nea^&AlJa9C8R(.sgSXl8[J^DVXK)ROYghK1B<:gkAs[B,BmQ;GXHtunWFr) +AFtZ#-b![YYJB%d635E?X,`H,pd_3Q6T*HpSonQW=9QAtTmY&!CKmS&b!!%sdfF3 +`;hKT0Ra1LiUKJ[$@C$fW0gA+'0VJ0=o8LX`AYs4)\_LbM_c#2*-XVr8K(,jUd:Z +?g$2:kVW6dNa6(n>7/V59`g2#Y!\-rU5Aq!U5Aq!U5Aq!U5Aq!U5Aq!U +5Aq!U5Aq!U5Aq!U5Aq!U5Ar&o#fEY[IT@=e^gW`HJpHLY7t%#@5W]=58-AcS"(,]e"BR9K"S!bAb,$ +AD71?>p@"Jml&_anX`1I0[0ruVCVCUm)N9/7!Q]6i0:1GZ%!$DFp#((k(HBH6VX' +=:18)7pgqsEM6>G\bajc\9c3;!^I$pd]_AF_d54id2o,/&r&g-YdJIFTUJ*:cI,, +ic=]X/#24_7pcL$J-&U-EV#'J2V[.WoO=11,G,aiHJc:-Nb`KQ*)^9P2>I?L00h= +O[u<@2K1r&NcHYML))W[p3NdO\A.eZS___.D/252.rKIDg&WE.-':[amTbbg36#o +-i%TX!;5cL79Tm-?h3'HaYfRjX&Wr.5`H0F5.Zd0)"<7t:^$9T^$O8'B!s+0qTK0 +u"lsgiL:S1onMosZ'IC)mDh;%3,<;CLV*nKpceX.nGh3b@qgi;4.po`UR,_BfVQ: +3D>,AUqeYeW7^3n=hqJu]SIE^H>#T9OL=N.)hU,Zf#)?_"B$jg'&^dhqB-M6*NW. +W/.1G&;Q>lZ]5?MXJAVVkL?cW]&:*AXS3[=[$.P,um]Z:Td@?*I??so"A&'hGO$G@h1 +$EhuelZ`7`GC;<_gf1Vm/QfDZ#n-K2CYrcG9PQ6j(S&ej-,Fl +SZ1?)E*.%_alS;+ij<::dR2b9.W5nluBn"nU@jPB?k\q'^ig[dDl+niJ:V06d>5R +Q,rr<%aO34@Z3gaNlPb#BiWq6,4&Eo4g;*u%2^u[nBVs6@n0S9I^8F;V"0od9Mr] +0#Jj]!;hfP&fbsfQ9L"ntUOK*;\ +$19rldl]ej4_bW]EpMGT2J?(u6#+,MKH=Dl*%J2V#i7cuC0>]qK68Zt/b;,41p;% +6Y.:sjVYs7.\^isO<#nJ?V3RdWgYK.tC#kRl@ca(A&kUF71L:"\L;"%?ZX&_#0't +m/XW*Rpm,>b*#SH6Cm\FAA39i7LkW]N(4n-LG*@B5l`;<`88aW_&oD)rEgn*[=WQ]%7ClIa@l`WG+2[>0cpZ/_ai;Jk'gQPt0'2N,i$@HXeGeMC[)/D2O@:I* +9c@rr>4Y^:d'Zid?H0nFsrV>jDj>LG._/]CTe[T"$&)DN?#)Fj +nQ4G*h/&1j^H&3MUX0bnoI#^B^9?$M(\f@VS5""^lW%>^0lC.u`_#9%.LG:@1\k* +8Hgi,npNKM0'UkSgDi?sbl;;L^(KPF"nkW3=MX-!U""3V24a-`VGCGjh[C!AuSlm +-q2:@d:Z'$ec']m"i2WX9%rr=TO\EY0B[[e_[D)]BLmk?U:XS +TQ^:p^\huT`)5.@\sALLTt$Hh!0,Ob2thCDjCqAeY$"s0O"=L%e*cOmgU:V$9]me#/#m[.6D( +k<=mpP`>L(i7^H]7BX*mbg2b/B9Nd]/0Y-HN5n&[HT"86h:qn=H\l)/\(!6CE.hm +;(RVJ6U0e?3EFH0:kMXsNen+_BLV5Sj'%]rj3D`rTq_gt'hPSd$$2E*B +G)go2CBP$T965-M8]^^WGIZh+oZ%tf[ZqgYQ!%R(Q'R=to\HZc[_"WsOJO;2M`fC +7a\GAL*f#X+dC_!2lT3eb<]YX"C+6d=JUg*'hA^`L!oWUj*0<5@]rsd$TBr]CJph +]AHaF-^-*=P'>*m;VGEPO(UO]0'3>LlRelJ)CGM-hAK?og[Qcb7?R3Qita&Y/;-^ +rtoR-"*%(Pc>JU:]Q6,lKRI48o&F-r+"1Nt]pUB9aN3Rb#%!Z'sOl0)Y+k,Q7iDS +tk/Sh$`1#K6.eH1mG_DCF`,/qr6:Fnu(OOE&&+I%s+>rMX`4Z\@UQ3m(4i5>$00N +M@(c+]]-ec.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX +!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%g +X!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%gX!.%h+Nf` +~> +%%EOF diff --git a/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.jpg b/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.jpg new file mode 100644 index 00000000000..ef67fb68b95 Binary files /dev/null and b/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.jpg differ diff --git a/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.pdf b/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.pdf new file mode 100644 index 00000000000..000c2303018 Binary files /dev/null and b/Ridges_3/doc_tex/Ridges_3/ellipsoid_ridges_mesh.pdf differ diff --git a/Ridges_3/doc_tex/Ridges_3/main.tex b/Ridges_3/doc_tex/Ridges_3/main.tex new file mode 100644 index 00000000000..a5809fdb14f --- /dev/null +++ b/Ridges_3/doc_tex/Ridges_3/main.tex @@ -0,0 +1,8 @@ +\chapter{Ridge extraction on meshes} +\label{chap:Ridges_3} +\ccChapterAuthor{Marc Pouget and Frédéric Cazals} + +\minitoc + +\input{Ridges_3/Ridges_3_user.tex} + \ No newline at end of file diff --git a/Ridges_3/include/CGAL/PolyhedralSurf.h b/Ridges_3/include/CGAL/PolyhedralSurf.h new file mode 100644 index 00000000000..b2b3a769fe3 --- /dev/null +++ b/Ridges_3/include/CGAL/PolyhedralSurf.h @@ -0,0 +1,226 @@ +#ifndef _POLYHEDRALSURF_H_ +#define _POLYHEDRALSURF_H_ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "PolyhedralSurf_operations.h" + +//---------------------------------------------------------------- +// A redefined items class for the Polyhedron_3 with a refined vertex +// class that contains a member for the mesh normal vector and a refined +// facet with a normal vector instead of the plane equation (this is +// an alternative solution instead of using Polyhedron_traits_with_normals_3). +//---------------------------------------------------------------- +// in addition vertices contains monge info +// some tags.... +template < class Refs, class Tag, class Pt, class FGeomTraits > +class My_vertex:public CGAL::HalfedgeDS_vertex_base < Refs, Tag, Pt > +{ + protected: + typedef typename Refs::Vertex Vertex; + typedef typename Refs::Halfedge Halfedge; + typedef typename Refs::Face Facet; + + typedef typename FGeomTraits::FT FT; + typedef typename FGeomTraits::Point_3 Point_3; + typedef typename FGeomTraits::Vector_3 Vector_3; + + protected: + //monge info + Vector_3 d1; //max ppal dir + Vector_3 d2; //min ppal dir; monge normal is then n_m=d1^d2, should be so that n_m.n_mesh>0 + FT k1, k2; //max/min ppal curv + FT b0, b3; //blue/red extremalities + FT P1, P2; //if fourth order quantities + + //this is for collecting i-th ring neighbours + char ring_tag; + int ring_index; + + public: + //monge info + const Vector _3 d1() const { return d1; } + Vector_3& d1() { return d1; } + const Vector _3 d2() const { return d2; } + Vector_3& d2() { return d2; } + const FT k1() const { return k1; } + FT& k1() { return k1; } + const FT k2() const { return k2; } + FT& k2() { return k2; } + const FT b0() const { return b0; } + FT& b0() { return b0; } + const FT b3() const { return b3; } + FT& b3() { return b3; } + const FT P1() const { return P1; } + FT& P1() { return P1; } + const FT P2() const { return P2; } + FT& P2() { return P2; } + + //this is for collecting i-th ring neighbours + void setRingIndex(int i) { ring_index = i; } + int getRingIndex() { return ring_index; } + void resetRingIndex() { ring_index = -1; } + void setRingTag() { ring_tag = 1; } + char getRingTag() { return ring_tag; } + + My_vertex(const Point_3 & pt): + CGAL::HalfedgeDS_vertex_base < Refs, Tag, Point_3 > (pt), + ring_tag(0), ring_index(-1) {} + My_vertex() {} +}; + +//---------------------------------------------------------------- +// Facet with normal and possibly more types. types are recovered +//from the FGeomTraits template arg +//---------------------------------------------------------------- +template < class Refs, class Tag, class FGeomTraits > +class My_facet:public CGAL::HalfedgeDS_face_base < Refs, Tag > +{ + //protected: +public: + typedef typename Refs::Vertex Vertex; + typedef typename Refs::Vertex_handle Vertex_handle; + typedef typename Refs::Halfedge Halfedge; + typedef typename Refs::Halfedge_handle Halfedge_handle; + + typedef typename FGeomTraits::Vector_3 Vector_3; + typedef typename FGeomTraits::Point_3 Point_3; + +public: + Vector_3 normal; + +public: + My_facet(): ring_index(-1) {} + Vector_3 & getUnitNormal() { return normal; } + void setNormal(Vector_3 & n) { normal = n; } + + //this is for collecting i-th ring neighbours +protected: + int ring_index; +public: + void setRingIndex(int i) { ring_index = i; } + int getRingIndex() { return ring_index; } + void resetRingIndex() { ring_index = -1; } +}; + +//---------------------------------------------------------------- +// Halfedge +//---------------------------------------------------------------- +template < class Refs, class Tprev, class Tvertex, class Tface, class FGeomTraits > +class My_halfedge:public CGAL::HalfedgeDS_halfedge_base < Refs, Tprev, Tvertex, Tface > +{ +protected: + typedef typename FGeomTraits::Point_3 Point_3; + typedef typename FGeomTraits::Vector_3 Vector_3; + +protected: + int ring_index; + double len; +public: + void setRingIndex(int i) { ring_index = i; } + int getRingIndex() {return ring_index; } + void resetRingIndex() {ring_index = -1; } +public: + My_halfedge(): ring_index(-1) {} + void setLength(double l) { len = l; } + double getLength() { return len; } +}; + +//------------------------------------------------ +// Wrappers [Vertex, Face, Halfedge] +//------------------------------------------------ +struct Wrappers_VFH:public CGAL::Polyhedron_items_3 { + // wrap vertex + template < class Refs, class Traits > struct Vertex_wrapper { + typedef struct { + public: + typedef typename Traits::Point_3 Point_3; + typedef typename Traits::Vector_3 Vector_3; + typedef typename Traits::Plane_3 Plane_3; + } FGeomTraits; + typedef typename Traits::Point_3 Point_3; + typedef My_vertex < Refs, CGAL::Tag_true, Point_3, FGeomTraits > Vertex; + }; + + // wrap face + //NOTE: [HDS, Face] renamed [Polyhedron, Facet] + template < class Refs, class Traits > struct Face_wrapper { + //typedef typename Traits::Vector_3 Vector_3; + //all types needed by the facet... + typedef struct { + public: + typedef typename Traits::Point_3 Point_3; + typedef typename Traits::Vector_3 Vector_3; + typedef typename Traits::Plane_3 Plane_3; + } FGeomTraits; + //custom type instantiated... + typedef My_facet < Refs, CGAL::Tag_true, FGeomTraits > Face; + }; + + // wrap halfedge + template < class Refs, class Traits > struct Halfedge_wrapper { + typedef struct { + public: + typedef typename Traits::Point_3 Point_3; + typedef typename Traits::Vector_3 Vector_3; + typedef typename Traits::Plane_3 Plane_3; + } FGeomTraits; + typedef My_halfedge < Refs, + CGAL::Tag_true, + CGAL::Tag_true, CGAL::Tag_true, FGeomTraits > Halfedge; + }; +}; + +//------------------------------------------------ +// Polyhedron +//------------------------------------------------ +//using standard Cartesian kernel +typedef double DFT; +typedef CGAL::Cartesian Data_Kernel; + +typedef CGAL::Polyhedron_3 < Data_Kernel, Wrappers_VFH > Polyhedron; +typedef Polyhedron::Vertex Vertex; +typedef Polyhedron::Vertex_handle Vertex_handle; +typedef Polyhedron::Halfedge Halfedge; +typedef Polyhedron::Halfedge_handle Halfedge_handle; + +typedef Polyhedron::Vertex_iterator Vertex_iterator; +typedef Polyhedron::Halfedge_iterator Halfedge_iterator; +typedef Polyhedron:: +Halfedge_around_vertex_circulator Halfedge_around_vertex_circulator; +typedef Polyhedron:: +Halfedge_around_facet_circulator Halfedge_around_facet_circulator; +typedef Polyhedron::Facet_iterator Facet_iterator; + +typedef Data_Kernel::Point_3 DPoint; +typedef Data_Kernel::Vector_3 Vector_3; +typedef Data_Kernel::Plane_3 Plane_3; +typedef Data_Kernel::Sphere_3 Sphere_3; + +/////////////////////class PolyhedralSurf/////////////////////////// +class PolyhedralSurf:public Polyhedron { +public: + typedef Data_Kernel::Point_3 DPoint; + typedef Data_Kernel::Vector_3 Vector_3; + typedef Data_Kernel::Plane_3 Plane_3; + +public: + static Vector_3 getHalfedge_vector(Halfedge * h); + + PolyhedralSurf() {} + void compute_edges_length(); + double compute_mean_edges_length_around_vertex(Vertex * v); + void compute_facets_normals(); + Vector_3 computeFacetsAverageUnitNormal(Vertex * v); +}; + +#endif diff --git a/Ridges_3/include/CGAL/algo.C b/Ridges_3/include/CGAL/algo.C new file mode 100644 index 00000000000..935371fd659 --- /dev/null +++ b/Ridges_3/include/CGAL/algo.C @@ -0,0 +1,379 @@ +#ifndef _RIDGE_3_H_ +#define _RIDGE_3_H_ + +#include + + +//Orient monge normal according to mesh normals. + +CGAL_BEGIN_NAMESPACE + + +enum Ridge_type {NONE=0, BLUE, RED, CREST, BE, BH, BC, RE, RH, RC}; + + +//--------------------------------------- +//Ridge_line : a connected sequence of edges crossed by a ridge, with type and weigths +//--------------------------------------- +template < class Poly > class Ridge_line +{ +public: + typedef typename Poly::Traits::FT FT; + typedef typename Poly::Vertex_handle Vertex_handle; + typedef typename Poly::Halfedge_handle Halfedge_handle; + typedef typename Poly::Facet_handle Facet_handle; + typedef std::pair ridge_he; + +protected: + Ridge_type line_type + std::list line; + FT strength; + FT sharpness; + +public: + const FT weight() const {return weight;} + const FT sharpness() const {return sharpness;} + std::list* line() { return &line;} + + //constructor + Ridge_line( Halfedge_handle h1, Halfedge_handle h2, Ridge_type r_type) : + line_type(r_type), strength(0.) + {}; + + //compute the barycentric coordinate of the xing point (blue or red) + //for he: p->q coord is st xing_point = coord*p + (1-coord)*q + FT bary_coord(Halfedge_handle he); + void compute_weight(char color); + void compute_sharpness(char color); + //When the line is extended with a he, the bary coord of the + //crossing point is computed, the pair (he,coord) is added and the + //weigths are updated + void addback( Halfedge_handle he); + void addfront( Halfedge_handle he); + +}; + +// IMPLEMENTATION OF Ridge_line members +////////////////////////////////////////////////////////////////////////////// + +//constructor +template < class Poly > +Ridge_line( Halfedge_handle h1, Halfedge_handle h2, Ridge_type r_type) : + line_type(r_type), strength(0.) +{ + line.push_back(h1); + addback(h2); +} + +template < class Poly > +void Ridge_line:: +addback( Halfedge_handle he) +{ + Halfedge_handle he_cur = ( --(line.end()) )->first; + FT coord = bary_coord(he); + FT coord_cur = bary_coord(he_cur); + Vertex_handle v_p = he->opposite()->vertex(), v_q = he->vertex(), + v_p_cur = he_cur->opposite()->vertex(), v_q_cur = he->vertex(); // he: p->q + FT k; + if ( (line_type == BE) || (line_type == BH) || (line_type == BC) ) { + k =( std::fabs(v_p->k1) * coord + std::fabs(v_q->k1) * (1-coord) )/2; + } + if ( (line_type == RE) || (line_type == RH) || (line_type == RC) ) { + k =( std::fabs(v_p->k2) * coord + std::fabs(v_q->k2) * (1-coord) )/2; + } + Vector_3 segment = (v_p->point()-ORIGIN)*coord + (v_q->point()-ORIGIN)*(1-coord) - + ((v_p_cur->point()-ORIGIN)*coord_cur + (v_q_cur->point()-ORIGIN)*(1-coord_cur)); + strength += k * CGAL::sqrt(segment * segment); + + line.push_back( pair(he, coord)); +} + +template < class Poly > +void Ridge_line:: +addfront( Halfedge_handle he) +{ + Halfedge_handle he_cur = ( line.begin() )->first; + FT coord = bary_coord(he); + FT coord_cur = bary_coord(he_cur); + Vertex_handle v_p = he->opposite()->vertex(), v_q = he->vertex(), + v_p_cur = he_cur->opposite()->vertex(), v_q_cur = he->vertex(); // he: p->q + FT k; + if ( (line_type == BE) || (line_type == BH) || (line_type == BC) ) { + k =( std::fabs(v_p->k1) * coord + std::fabs(v_q->k1) * (1-coord) )/2; + } + if ( (line_type == RE) || (line_type == RH) || (line_type == RC) ) { + k =( std::fabs(v_p->k2) * coord + std::fabs(v_q->k2) * (1-coord) )/2; + } + Vector_3 segment = (v_p->point()-ORIGIN)*coord + (v_q->point()-ORIGIN)*(1-coord) - + ((v_p_cur->point()-ORIGIN)*coord_cur + (v_q_cur->point()-ORIGIN)*(1-coord_cur)); + strength += k * CGAL::sqrt(segment * segment); + + line.push_front( pair(he, coord)); +} + + +template < class Poly > +FT Ridge_line:: +bary_coord(Halfedge_handle he) +{ + FT b_p, b_q; // extremalities at p and q for he: p->q + if ( (line_type == BE) || (line_type == BH) || (line_type == BC) ) { + b_p = he->opposite()->vertex()->b0(); + b_q = he->vertex()->b0(); + } + if ( (line_type == RE) || (line_type == RH) || (line_type == RC) ) { + b_p = he->opposite()->vertex()->b3(); + b_q = he->vertex()->b3(); + } + return std::fabs(b_q) / ( std::fabs(b_q) + std::fabs(b_p) ); +} + + +/////////Ridge_approximation////////////////////////////////////////// + +//Find BLUE ridges (Elliptic or Hyperbolic) +//do the same for RED and CREST +//iterate on P facets, find a non-visited, regular, 2BXing triangle, +//follow non-visited, regular, 2BXing triangles in both sens to create +//a Ridge line. +//Each time a edge is added the strength of the current line is updated +// + length(edge)*|k| +void +compute_ridges(Ridge_type r_type) +{ + //set all facets non visited + + + Facet_iterator itb = P.facets_begin(), ite = P.facets_end(); + for(;itb!=ite;itb++) + { + Facet_handle f= &(*itb); + if (f->is_visited()) continue; + f->set_visited(true); + Halfedge_handle h1, h2, curhe1, curhe2, curhe; + + //h1 h2 are the hedges crossed if any, r_type should be BLUE, + //RED or CREST ; cur_ridge_type should be BE, BH, BC, RE, RH, RC or NONE + Ridge_type cur_ridge_type = facet_ridge_type(f,h1,h2,r_type) + if ( cur_ridge_type == NONE ) continue; + + //When a he is inserted in a Ridge_line, a pair + //is created and the weight(s) are updated + Ridge_line *cur_ridge_line = new Ridge_line(h1,h2,cur_ridge_type); + *ridge_lines_it++ = cur_ridge_line; + + //next triangle adjacent to h1 (push_front) + if ( !(h1->is_border_edge()) ) + { + f = h1->opposite()->facet(); + curhe = h1; + while (cur_ridge_type == facet_ridge_type(f,curhe1,curhe2,r_type)) + { + //follow the ridge from curhe + if (f->is_visited()) break; + f->set_visited(true); + if (curhe->opposite() == curhe1) curhe = curhe2; + else curhe = curhe1; + cur_ridge_line->addfront(curhe); + if ( !(curhe->is_border_edge()) ) f = + curhe->opposite()->facet(); + else break; + } + //exit from the while if + //1. border + //2. not same type, then do not set visisted cause a BE + // follows a BH + } + + //next triangle adjacent to h2 (push_back) + if ( !(h2->is_border_edge()) ) + { + f = h2->opposite()->facet(); + curhe = h2; + while (cur_ridge_type == facet_ridge_type(f,curhe1,curhe2,r_type)) + { + //follow the ridge from curhe + if (f->is_visitedB()) break; + f->set_visitedB(true); + if (curhe->opposite() == curhe1) curhe = curhe2; + else curhe = curhe1; + cur_ridge_line->addback(curhe); + if ( !(curhe->is_border_edge()) ) f = + curhe->opposite()->facet(); + else break; + } + } + } +} + + +Ridge_type +facet_ridge_type(Facet_handle f, Halfedge_handle& he1, Halfedge_handle& + he2, Ridge_type r_type) +{ + //polyhedral data + //we have v1--h1-->v2--h2-->v3--h3-->v1 + Halfedge_handle h1 = f->halfedge(), h2, h3; + Vertex_handle v1, v2, v3; + v2 = h1->vertex(); + h2 = h1->next(); + v3 = h2->vertex(); + h3 = h2->next(); + v1 = h3->vertex(); + + //check for regular facet + if ( v1->d1()*v2->d1() * v1->d1()*v3->d1() * v2->d1()*v3->d1() < 0 ) return NONE; + + //determine potential crest color + Ridge_type crest_color = NONE; + if (r_type == CREST) + { + if ( std::fabs(v1->k1()+v2->k1()+v3->k1()) > std::fabs(v1->k2()+v2->k2()+v3->k2()) ) + crest_color = BC; + if ( std::fabs(v1->k1()+v2->k1()+v3->k1()) < std::fabs(v1->k2()+v2->k2()+v3->k2()) ) + crest_color = RC; + if ( std::fabs(v1->k1()+v2->k1()+v3->k1()) = std::fabs(v1->k2()+v2->k2()+v3->k2()) ) + return NONE; + } + + //compute Xing on the 3 edges + bool h1_is_crossed, h2_is_crossed, h3_is_crossed; + if ( r_type == BLUE || crest_color == BC ) + { + xing_on_edge(h1, h1_is_crossed, BLUE); + xing_on_edge(h2, h2_is_crossed, BLUE); + xing_on_edge(h3, h3_is_crossed, BLUE); + } + if ( r_type == RED || crest_color == RC ) + { + xing_on_edge(h1, h1_is_crossed, RED); + xing_on_edge(h2, h2_is_crossed, RED); + xing_on_edge(h3, h3_is_crossed, RED); + } + + //test of 2Xing + if ( !(h1_is_crossed && h2_is_crossed && !h3_is_crossed) && + !(h1_is_crossed && !h2_is_crossed && h3_is_crossed) && + (!h1_is_crossed && h2_is_crossed && h3_is_crossed) ) + return NONE; + if (h1_is_crossed && h2_is_crossed && !h3_is_crossed) + { + he1 = h1; + he2 = h2; + } + if (h1_is_crossed && !h2_is_crossed && h3_is_crossed) + { + he1 = h1; + he2 = h3; + } + if (!h1_is_crossed && h2_is_crossed && h3_is_crossed) + { + he1 = h2; + he2 = h3; + } + + Vertex_handle v_p1 = he1->opposite()->vertex(), v_q1 = he1->vertex(), + v_p2 = he2->opposite()->vertex(), v_q2 = he2->vertex(); // he1: p1->q1 + + if ( r_type == BLUE || crest_color == BC ) + { + FT coord1 = std::fabs(v_q1->b0()) / ( std::fabs(v_p1->b0()) + std::fabs(v_q1->b0()) ), + coord2 = std::fabs(v_q2->b0()) / ( std::fabs(v_p2->b0()) + std::fabs(v_q2->b0()) ); + Vector_3 r1 = (v_p1->point()-ORIGIN)*coord1 + (v_q1->point()-ORIGIN)*(1-coord1), + r2 = (v_p2->point()-ORIGIN)*coord2 + (v_q2->point()-ORIGIN)*(1-coord2); + int b_sign = b_sign_pointing_to_ridge(v1, v2, v3, r1, r2, BLUE); + if (b_sign == 1) { if (r_type == BLUE) return BE; else return BC;} + if (b_sign == -1) return BH; + } + if ( r_type == RED || crest_color == RC ) + { + FT coord1 = std::fabs(v_q1->b3()) / ( std::fabs(v_p1->b3()) + std::fabs(v_q1->b3()) ), + coord2 = std::fabs(v_q2->b3()) / ( std::fabs(v_p2->b3()) + std::fabs(v_q2->b3()) ); + Vector_3 r1 = (v_p1->point()-ORIGIN)*coord1 + (v_q1->point()-ORIGIN)*(1-coord1), + r2 = (v_p2->point()-ORIGIN)*coord2 + (v_q2->point()-ORIGIN)*(1-coord2); + int b_sign = b_sign_pointing_to_ridge(v1, v2, v3, r1, r2, RED); + if (b_sign == -1) { if (r_type == RED) return RE; else return RC;} + if (b_sign == 1) return BH; + } + assert(0); +} + +void +xing_on_edge(Halfedge_handle he, bool& is_crossed, Ridge_type color) +{ + is_crossed = false; + FT sign; + FT b_p, b_q; // extremalities at p and q for he: p->q + Vector_3 d_p = he->opposite()->vertex()->d1(), + d_q = he->vertex()->d1(); //ppal dir + if ( color == BLUE ) { + b_p = he->opposite()->vertex()->b0(); + b_q = he->vertex()->b0(); + } + else { + b_p = he->opposite()->vertex()->b3(); + b_q = he->vertex()->b3(); + } + if ( b_p == 0 && b_q == 0 ) return; + if ( b_p == 0 && b_q !=0 ) sign = d_p*d_q * b_q; + if ( b_p != 0 && b_q ==0 ) sign = d_p*d_q * b_p; + if ( b_p != 0 && b_q !=0 ) sign = d_p*d_q * b_p * b_q; + if ( sign < 0 ) is_crossed = true; +} + + + +//for a ridge segment in a triangle [r1,r2], let r = r2 - r1 and normalize, +//the projection of a point p on the line (r1,r2) is pp=r1+tr, with t=(p-r1)*r +//then the vector v starting at p is pointing to the ridge line (r1,r2) if +//(pp-p)*v >0 +int +b_sign_pointing_to_ridge(Vertex_handle v1, Vertex_handle v2, Vertex_handle v3, + Vector_3 r1, Vector_3 r2, Ridge_type color) +{ + Vector_3 r = r2 - r1, dv1, dv2, dv3; + FT bv1, bv2, bv3; + if ( color == BLUE ) { + bv1 = v1->b0(); + bv2 = v2->b0(); + bv3 = v3->b0(); + dv1 = v1->d1(); + dv2 = v2->d1(); + dv3 = v3->d1(); + } + else { + bv1 = v1->b3(); + bv2 = v2->b3(); + bv3 = v3->b3(); + dv1 = v1->d2(); + dv2 = v2->d2(); + dv3 = v3->d2(); + } + if ( r !=0 ) r = r/CGAL::sqrt(r*r); + FT sign1, sign2, sign3; + sign1 = (r1 - (v1->point()-ORIGIN) + (((v1->point()-ORIGIN)-r1)*r)*r )*dv1; + sign2 = (r1 - (v2->point()-ORIGIN) + (((v2->point()-ORIGIN)-r1)*r)*r )*dv2; + sign3 = (r1 - (v3->point()-ORIGIN) + (((v3->point()-ORIGIN)-r1)*r)*r )*dv3; + + int compt = 0; + if ( sign1 > 0 ) compt++; else if (sign1 < 0) compt--; + if ( sign2 > 0 ) compt++; else if (sign2 < 0) compt--; + if ( sign3 > 0 ) compt++; else if (sign3 < 0) compt--; + + if (compt > 0) return 1; else return -1; +} + + + + + + + + + + + + +CGAL_END_NAMESPACE + +#endif diff --git a/Ridges_3/maintainer b/Ridges_3/maintainer new file mode 100644 index 00000000000..3c9a7df9f51 --- /dev/null +++ b/Ridges_3/maintainer @@ -0,0 +1,2 @@ +Marc Pouget +Frédéric Cazals \ No newline at end of file