123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065 |
- // -----------------------------------------------------------------------
- // <copyright file="NewLocation.cs">
- // Original code by Hale Erten and Alper Üngör, http://www.cise.ufl.edu/~ungor/aCute/index.html
- // Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
- // </copyright>
- // -----------------------------------------------------------------------
- namespace UnityEngine.U2D.Animation.TriangleNet
- {
- using System;
- using Animation.TriangleNet.Topology;
- using Animation.TriangleNet.Geometry;
- using Animation.TriangleNet.Tools;
- /// <summary>
- /// Find new Steiner point locations.
- /// </summary>
- /// <remarks>
- /// http://www.cise.ufl.edu/~ungor/aCute/index.html
- /// </remarks>
- class NewLocation
- {
- const double EPS = 1e-50;
- IPredicates predicates;
- Mesh mesh;
- Behavior behavior;
- // Work arrays for wegde intersection
- double[] petalx = new double[20];
- double[] petaly = new double[20];
- double[] petalr = new double[20];
- double[] wedges = new double[500];
- double[] initialConvexPoly = new double[500];
- // Work arrays for smoothing
- double[] points_p = new double[500];
- double[] points_q = new double[500];
- double[] points_r = new double[500];
- // Work arrays for convex polygon split
- double[] poly1 = new double[100];
- double[] poly2 = new double[100];
- double[][] polys = new double[3][];
- public NewLocation(Mesh mesh, IPredicates predicates)
- {
- this.mesh = mesh;
- this.predicates = predicates;
- this.behavior = mesh.behavior;
- }
- /// <summary>
- /// Find a new location for a Steiner point.
- /// </summary>
- /// <param name="org"></param>
- /// <param name="dest"></param>
- /// <param name="apex"></param>
- /// <param name="xi"></param>
- /// <param name="eta"></param>
- /// <param name="offcenter"></param>
- /// <param name="badotri"></param>
- /// <returns></returns>
- public Point FindLocation(Vertex org, Vertex dest, Vertex apex,
- ref double xi, ref double eta, bool offcenter, Otri badotri)
- {
- // Based on using -U switch, call the corresponding function
- if (behavior.MaxAngle == 0.0)
- {
- // Disable the "no max angle" code. It may return weired vertex locations.
- return FindNewLocationWithoutMaxAngle(org, dest, apex, ref xi, ref eta, true, badotri);
- }
- // With max angle
- return FindNewLocation(org, dest, apex, ref xi, ref eta, true, badotri);
- }
- /// <summary>
- /// Find a new location for a Steiner point.
- /// </summary>
- /// <param name="torg"></param>
- /// <param name="tdest"></param>
- /// <param name="tapex"></param>
- /// <param name="circumcenter"></param>
- /// <param name="xi"></param>
- /// <param name="eta"></param>
- /// <param name="offcenter"></param>
- /// <param name="badotri"></param>
- private Point FindNewLocationWithoutMaxAngle(Vertex torg, Vertex tdest, Vertex tapex,
- ref double xi, ref double eta, bool offcenter, Otri badotri)
- {
- double offconstant = behavior.offconstant;
- // for calculating the distances of the edges
- double xdo, ydo, xao, yao, xda, yda;
- double dodist, aodist, dadist;
- // for exact calculation
- double denominator;
- double dx, dy, dxoff, dyoff;
- ////////////////////////////// HALE'S VARIABLES //////////////////////////////
- // keeps the difference of coordinates edge
- double xShortestEdge = 0, yShortestEdge = 0;
- // keeps the square of edge lengths
- double shortestEdgeDist = 0, middleEdgeDist = 0, longestEdgeDist = 0;
- // keeps the vertices according to the angle incident to that vertex in a triangle
- Point smallestAngleCorner, middleAngleCorner, largestAngleCorner;
- // keeps the type of orientation if the triangle
- int orientation = 0;
- // keeps the coordinates of circumcenter of itself and neighbor triangle circumcenter
- Point myCircumcenter, neighborCircumcenter;
- // keeps if bad triangle is almost good or not
- int almostGood = 0;
- // keeps the cosine of the largest angle
- double cosMaxAngle;
- bool isObtuse; // 1: obtuse 0: nonobtuse
- // keeps the radius of petal
- double petalRadius;
- // for calculating petal center
- double xPetalCtr_1, yPetalCtr_1, xPetalCtr_2, yPetalCtr_2, xPetalCtr, yPetalCtr, xMidOfShortestEdge, yMidOfShortestEdge;
- double dxcenter1, dycenter1, dxcenter2, dycenter2;
- // for finding neighbor
- Otri neighborotri = default(Otri);
- double[] thirdPoint = new double[2];
- //int neighborNotFound = -1;
- bool neighborNotFound;
- // for keeping the vertices of the neighbor triangle
- Vertex neighborvertex_1;
- Vertex neighborvertex_2;
- Vertex neighborvertex_3;
- // dummy variables
- double xi_tmp = 0, eta_tmp = 0;
- //vertex thirdVertex;
- // for petal intersection
- double vector_x, vector_y, xMidOfLongestEdge, yMidOfLongestEdge, inter_x, inter_y;
- double[] p = new double[5], voronoiOrInter = new double[4];
- bool isCorrect;
- // for vector calculations in perturbation
- double ax, ay, d;
- double pertConst = 0.06; // perturbation constant
- double lengthConst = 1; // used at comparing circumcenter's distance to proposed point's distance
- double justAcute = 1; // used for making the program working for one direction only
- // for smoothing
- int relocated = 0;// used to differentiate between calling the deletevertex and just proposing a steiner point
- double[] newloc = new double[2]; // new location suggested by smoothing
- double origin_x = 0, origin_y = 0; // for keeping torg safe
- Otri delotri; // keeping the original orientation for relocation process
- // keeps the first and second direction suggested points
- double dxFirstSuggestion, dyFirstSuggestion, dxSecondSuggestion, dySecondSuggestion;
- // second direction variables
- double xMidOfMiddleEdge, yMidOfMiddleEdge;
- ////////////////////////////// END OF HALE'S VARIABLES //////////////////////////////
- Statistic.CircumcenterCount++;
- // Compute the circumcenter of the triangle.
- xdo = tdest.x - torg.x;
- ydo = tdest.y - torg.y;
- xao = tapex.x - torg.x;
- yao = tapex.y - torg.y;
- xda = tapex.x - tdest.x;
- yda = tapex.y - tdest.y;
- // keeps the square of the distances
- dodist = xdo * xdo + ydo * ydo;
- aodist = xao * xao + yao * yao;
- dadist = (tdest.x - tapex.x) * (tdest.x - tapex.x) +
- (tdest.y - tapex.y) * (tdest.y - tapex.y);
- // checking if the user wanted exact arithmetic or not
- if (Behavior.NoExact)
- {
- denominator = 0.5 / (xdo * yao - xao * ydo);
- }
- else
- {
- // Use the counterclockwise() routine to ensure a positive (and
- // reasonably accurate) result, avoiding any possibility of
- // division by zero.
- denominator = 0.5 / predicates.CounterClockwise(tdest, tapex, torg);
- // Don't count the above as an orientation test.
- Statistic.CounterClockwiseCount--;
- }
- // calculate the circumcenter in terms of distance to origin point
- dx = (yao * dodist - ydo * aodist) * denominator;
- dy = (xdo * aodist - xao * dodist) * denominator;
- // for debugging and for keeping circumcenter to use later
- // coordinate value of the circumcenter
- myCircumcenter = new Point(torg.x + dx, torg.y + dy);
- delotri = badotri; // save for later
- ///////////////// FINDING THE ORIENTATION OF TRIANGLE //////////////////
- // Find the (squared) length of the triangle's shortest edge. This
- // serves as a conservative estimate of the insertion radius of the
- // circumcenter's parent. The estimate is used to ensure that
- // the algorithm terminates even if very small angles appear in
- // the input PSLG.
- // find the orientation of the triangle, basically shortest and longest edges
- orientation = LongestShortestEdge(aodist, dadist, dodist);
- //printf("org: (%f,%f), dest: (%f,%f), apex: (%f,%f)\n",torg[0],torg[1],tdest[0],tdest[1],tapex[0],tapex[1]);
- /////////////////////////////////////////////////////////////////////////////////////////////
- // 123: shortest: aodist // 213: shortest: dadist // 312: shortest: dodist //
- // middle: dadist // middle: aodist // middle: aodist //
- // longest: dodist // longest: dodist // longest: dadist //
- // 132: shortest: aodist // 231: shortest: dadist // 321: shortest: dodist //
- // middle: dodist // middle: dodist // middle: dadist //
- // longest: dadist // longest: aodist // longest: aodist //
- /////////////////////////////////////////////////////////////////////////////////////////////
- switch (orientation)
- {
- case 123: // assign necessary information
- /// smallest angle corner: dest
- /// largest angle corner: apex
- xShortestEdge = xao; yShortestEdge = yao;
- shortestEdgeDist = aodist;
- middleEdgeDist = dadist;
- longestEdgeDist = dodist;
- smallestAngleCorner = tdest;
- middleAngleCorner = torg;
- largestAngleCorner = tapex;
- break;
- case 132: // assign necessary information
- /// smallest angle corner: dest
- /// largest angle corner: org
- xShortestEdge = xao; yShortestEdge = yao;
- shortestEdgeDist = aodist;
- middleEdgeDist = dodist;
- longestEdgeDist = dadist;
- smallestAngleCorner = tdest;
- middleAngleCorner = tapex;
- largestAngleCorner = torg;
- break;
- case 213: // assign necessary information
- /// smallest angle corner: org
- /// largest angle corner: apex
- xShortestEdge = xda; yShortestEdge = yda;
- shortestEdgeDist = dadist;
- middleEdgeDist = aodist;
- longestEdgeDist = dodist;
- smallestAngleCorner = torg;
- middleAngleCorner = tdest;
- largestAngleCorner = tapex;
- break;
- case 231: // assign necessary information
- /// smallest angle corner: org
- /// largest angle corner: dest
- xShortestEdge = xda; yShortestEdge = yda;
- shortestEdgeDist = dadist;
- middleEdgeDist = dodist;
- longestEdgeDist = aodist;
- smallestAngleCorner = torg;
- middleAngleCorner = tapex;
- largestAngleCorner = tdest;
- break;
- case 312: // assign necessary information
- /// smallest angle corner: apex
- /// largest angle corner: org
- xShortestEdge = xdo; yShortestEdge = ydo;
- shortestEdgeDist = dodist;
- middleEdgeDist = aodist;
- longestEdgeDist = dadist;
- smallestAngleCorner = tapex;
- middleAngleCorner = tdest;
- largestAngleCorner = torg;
- break;
- case 321: // assign necessary information
- default: // TODO: is this safe?
- /// smallest angle corner: apex
- /// largest angle corner: dest
- xShortestEdge = xdo; yShortestEdge = ydo;
- shortestEdgeDist = dodist;
- middleEdgeDist = dadist;
- longestEdgeDist = aodist;
- smallestAngleCorner = tapex;
- middleAngleCorner = torg;
- largestAngleCorner = tdest;
- break;
- }// end of switch
- // check for offcenter condition
- if (offcenter && (offconstant > 0.0))
- {
- // origin has the smallest angle
- if (orientation == 213 || orientation == 231)
- {
- // Find the position of the off-center, as described by Alper Ungor.
- dxoff = 0.5 * xShortestEdge - offconstant * yShortestEdge;
- dyoff = 0.5 * yShortestEdge + offconstant * xShortestEdge;
- // If the off-center is closer to destination than the
- // circumcenter, use the off-center instead.
- /// doubleLY BAD CASE ///
- if (dxoff * dxoff + dyoff * dyoff <
- (dx - xdo) * (dx - xdo) + (dy - ydo) * (dy - ydo))
- {
- dx = xdo + dxoff;
- dy = ydo + dyoff;
- }
- /// ALMOST GOOD CASE ///
- else
- {
- almostGood = 1;
- }
- // destination has the smallest angle
- }
- else if (orientation == 123 || orientation == 132)
- {
- // Find the position of the off-center, as described by Alper Ungor.
- dxoff = 0.5 * xShortestEdge + offconstant * yShortestEdge;
- dyoff = 0.5 * yShortestEdge - offconstant * xShortestEdge;
- // If the off-center is closer to the origin than the
- // circumcenter, use the off-center instead.
- /// doubleLY BAD CASE ///
- if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy)
- {
- dx = dxoff;
- dy = dyoff;
- }
- /// ALMOST GOOD CASE ///
- else
- {
- almostGood = 1;
- }
- // apex has the smallest angle
- }
- else
- {//orientation == 312 || orientation == 321
- // Find the position of the off-center, as described by Alper Ungor.
- dxoff = 0.5 * xShortestEdge - offconstant * yShortestEdge;
- dyoff = 0.5 * yShortestEdge + offconstant * xShortestEdge;
- // If the off-center is closer to the origin than the
- // circumcenter, use the off-center instead.
- /// doubleLY BAD CASE ///
- if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy)
- {
- dx = dxoff;
- dy = dyoff;
- }
- /// ALMOST GOOD CASE ///
- else
- {
- almostGood = 1;
- }
- }
- }
- // if the bad triangle is almost good, apply our approach
- if (almostGood == 1)
- {
- /// calculate cosine of largest angle ///
- cosMaxAngle = (middleEdgeDist + shortestEdgeDist - longestEdgeDist) / (2 * Math.Sqrt(middleEdgeDist) * Math.Sqrt(shortestEdgeDist));
- if (cosMaxAngle < 0.0)
- {
- // obtuse
- isObtuse = true;
- }
- else if (Math.Abs(cosMaxAngle - 0.0) <= EPS)
- {
- // right triangle (largest angle is 90 degrees)
- isObtuse = true;
- }
- else
- {
- // nonobtuse
- isObtuse = false;
- }
- /// RELOCATION (LOCAL SMOOTHING) ///
- /// check for possible relocation of one of triangle's points ///
- relocated = DoSmoothing(delotri, torg, tdest, tapex, ref newloc);
- /// if relocation is possible, delete that vertex and insert a vertex at the new location ///
- if (relocated > 0)
- {
- Statistic.RelocationCount++;
- dx = newloc[0] - torg.x;
- dy = newloc[1] - torg.y;
- origin_x = torg.x; // keep for later use
- origin_y = torg.y;
- switch (relocated)
- {
- case 1:
- //printf("Relocate: (%f,%f)\n", torg[0],torg[1]);
- mesh.DeleteVertex(ref delotri);
- break;
- case 2:
- //printf("Relocate: (%f,%f)\n", tdest[0],tdest[1]);
- delotri.Lnext();
- mesh.DeleteVertex(ref delotri);
- break;
- case 3:
- //printf("Relocate: (%f,%f)\n", tapex[0],tapex[1]);
- delotri.Lprev();
- mesh.DeleteVertex(ref delotri);
- break;
- }
- }
- else
- {
- // calculate radius of the petal according to angle constraint
- // first find the visible region, PETAL
- // find the center of the circle and radius
- petalRadius = Math.Sqrt(shortestEdgeDist) / (2 * Math.Sin(behavior.MinAngle * Math.PI / 180.0));
- /// compute two possible centers of the petal ///
- // finding the center
- // first find the middle point of smallest edge
- xMidOfShortestEdge = (middleAngleCorner.x + largestAngleCorner.x) / 2.0;
- yMidOfShortestEdge = (middleAngleCorner.y + largestAngleCorner.y) / 2.0;
- // two possible centers
- xPetalCtr_1 = xMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.y -
- largestAngleCorner.y) / Math.Sqrt(shortestEdgeDist);
- yPetalCtr_1 = yMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.x -
- middleAngleCorner.x) / Math.Sqrt(shortestEdgeDist);
- xPetalCtr_2 = xMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.y -
- largestAngleCorner.y) / Math.Sqrt(shortestEdgeDist);
- yPetalCtr_2 = yMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.x -
- middleAngleCorner.x) / Math.Sqrt(shortestEdgeDist);
- // find the correct circle since there will be two possible circles
- // calculate the distance to smallest angle corner
- dxcenter1 = (xPetalCtr_1 - smallestAngleCorner.x) * (xPetalCtr_1 - smallestAngleCorner.x);
- dycenter1 = (yPetalCtr_1 - smallestAngleCorner.y) * (yPetalCtr_1 - smallestAngleCorner.y);
- dxcenter2 = (xPetalCtr_2 - smallestAngleCorner.x) * (xPetalCtr_2 - smallestAngleCorner.x);
- dycenter2 = (yPetalCtr_2 - smallestAngleCorner.y) * (yPetalCtr_2 - smallestAngleCorner.y);
- // whichever is closer to smallest angle corner, it must be the center
- if (dxcenter1 + dycenter1 <= dxcenter2 + dycenter2)
- {
- xPetalCtr = xPetalCtr_1; yPetalCtr = yPetalCtr_1;
- }
- else
- {
- xPetalCtr = xPetalCtr_2; yPetalCtr = yPetalCtr_2;
- }
- /// find the third point of the neighbor triangle ///
- neighborNotFound = GetNeighborsVertex(badotri, middleAngleCorner.x, middleAngleCorner.y,
- smallestAngleCorner.x, smallestAngleCorner.y, ref thirdPoint, ref neighborotri);
- /// find the circumcenter of the neighbor triangle ///
- dxFirstSuggestion = dx; // if we cannot find any appropriate suggestion, we use circumcenter
- dyFirstSuggestion = dy;
- // if there is a neighbor triangle
- if (!neighborNotFound)
- {
- neighborvertex_1 = neighborotri.Org();
- neighborvertex_2 = neighborotri.Dest();
- neighborvertex_3 = neighborotri.Apex();
- // now calculate neighbor's circumcenter which is the voronoi site
- neighborCircumcenter = predicates.FindCircumcenter(neighborvertex_1, neighborvertex_2, neighborvertex_3,
- ref xi_tmp, ref eta_tmp);
- /// compute petal and Voronoi edge intersection ///
- // in order to avoid degenerate cases, we need to do a vector based calculation for line
- vector_x = (middleAngleCorner.y - smallestAngleCorner.y);//(-y, x)
- vector_y = smallestAngleCorner.x - middleAngleCorner.x;
- vector_x = myCircumcenter.x + vector_x;
- vector_y = myCircumcenter.y + vector_y;
- // by intersecting bisectors you will end up with the one you want to walk on
- // then this line and circle should be intersected
- CircleLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y,
- xPetalCtr, yPetalCtr, petalRadius, ref p);
- /// choose the correct intersection point ///
- // calculate middle point of the longest edge(bisector)
- xMidOfLongestEdge = (middleAngleCorner.x + smallestAngleCorner.x) / 2.0;
- yMidOfLongestEdge = (middleAngleCorner.y + smallestAngleCorner.y) / 2.0;
- // we need to find correct intersection point, since line intersects circle twice
- isCorrect = ChooseCorrectPoint(xMidOfLongestEdge, yMidOfLongestEdge, p[3], p[4],
- myCircumcenter.x, myCircumcenter.y, isObtuse);
- // make sure which point is the correct one to be considered
- if (isCorrect)
- {
- inter_x = p[3];
- inter_y = p[4];
- }
- else
- {
- inter_x = p[1];
- inter_y = p[2];
- }
- /// check if there is a Voronoi vertex between before intersection ///
- // check if the voronoi vertex is between the intersection and circumcenter
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y,
- neighborCircumcenter.x, neighborCircumcenter.y, ref voronoiOrInter);
- /// determine the point to be suggested ///
- if (p[0] > 0.0)
- { // there is at least one intersection point
- // if it is between circumcenter and intersection
- // if it returns 1.0 this means we have a voronoi vertex within feasible region
- if (Math.Abs(voronoiOrInter[0] - 1.0) <= EPS)
- {
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, neighborCircumcenter.x, neighborCircumcenter.y))
- {
- // go back to circumcenter
- dxFirstSuggestion = dx;
- dyFirstSuggestion = dy;
- }
- else
- { // we are not creating a bad triangle
- // neighbor's circumcenter is suggested
- dxFirstSuggestion = voronoiOrInter[2] - torg.x;
- dyFirstSuggestion = voronoiOrInter[3] - torg.y;
- }
- }
- else
- { // there is no voronoi vertex between intersection point and circumcenter
- if (IsBadTriangleAngle(largestAngleCorner.x, largestAngleCorner.y, middleAngleCorner.x, middleAngleCorner.y, inter_x, inter_y))
- {
- // if it is inside feasible region, then insert v2
- // apply perturbation
- // find the distance between circumcenter and intersection point
- d = Math.Sqrt((inter_x - myCircumcenter.x) * (inter_x - myCircumcenter.x) +
- (inter_y - myCircumcenter.y) * (inter_y - myCircumcenter.y));
- // then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.x - inter_x;
- ay = myCircumcenter.y - inter_y;
- ax = ax / d;
- ay = ay / d;
- // now calculate the new intersection point which is perturbated towards the circumcenter
- inter_x = inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
- inter_y = inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
- {
- // go back to circumcenter
- dxFirstSuggestion = dx;
- dyFirstSuggestion = dy;
- }
- else
- {
- // intersection point is suggested
- dxFirstSuggestion = inter_x - torg.x;
- dyFirstSuggestion = inter_y - torg.y;
- }
- }
- else
- {
- // intersection point is suggested
- dxFirstSuggestion = inter_x - torg.x;
- dyFirstSuggestion = inter_y - torg.y;
- }
- }
- /// if it is an acute triangle, check if it is a good enough location ///
- // for acute triangle case, we need to check if it is ok to use either of them
- if ((smallestAngleCorner.x - myCircumcenter.x) * (smallestAngleCorner.x - myCircumcenter.x) +
- (smallestAngleCorner.y - myCircumcenter.y) * (smallestAngleCorner.y - myCircumcenter.y) >
- lengthConst * ((smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y))))
- {
- // use circumcenter
- dxFirstSuggestion = dx;
- dyFirstSuggestion = dy;
- }// else we stick to what we have found
- }// intersection point
- }// if it is on the boundary, meaning no neighbor triangle in this direction, try other direction
- /// DO THE SAME THING FOR THE OTHER DIRECTION ///
- /// find the third point of the neighbor triangle ///
- neighborNotFound = GetNeighborsVertex(badotri, largestAngleCorner.x, largestAngleCorner.y,
- smallestAngleCorner.x, smallestAngleCorner.y, ref thirdPoint, ref neighborotri);
- /// find the circumcenter of the neighbor triangle ///
- dxSecondSuggestion = dx; // if we cannot find any appropriate suggestion, we use circumcenter
- dySecondSuggestion = dy;
- // if there is a neighbor triangle
- if (!neighborNotFound)
- {
- neighborvertex_1 = neighborotri.Org();
- neighborvertex_2 = neighborotri.Dest();
- neighborvertex_3 = neighborotri.Apex();
- // now calculate neighbor's circumcenter which is the voronoi site
- neighborCircumcenter = predicates.FindCircumcenter(neighborvertex_1, neighborvertex_2, neighborvertex_3,
- ref xi_tmp, ref eta_tmp);
- /// compute petal and Voronoi edge intersection ///
- // in order to avoid degenerate cases, we need to do a vector based calculation for line
- vector_x = (largestAngleCorner.y - smallestAngleCorner.y);//(-y, x)
- vector_y = smallestAngleCorner.x - largestAngleCorner.x;
- vector_x = myCircumcenter.x + vector_x;
- vector_y = myCircumcenter.y + vector_y;
- // by intersecting bisectors you will end up with the one you want to walk on
- // then this line and circle should be intersected
- CircleLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y,
- xPetalCtr, yPetalCtr, petalRadius, ref p);
- /// choose the correct intersection point ///
- // calcuwedgeslate middle point of the longest edge(bisector)
- xMidOfMiddleEdge = (largestAngleCorner.x + smallestAngleCorner.x) / 2.0;
- yMidOfMiddleEdge = (largestAngleCorner.y + smallestAngleCorner.y) / 2.0;
- // we need to find correct intersection point, since line intersects circle twice
- // this direction is always ACUTE
- isCorrect = ChooseCorrectPoint(xMidOfMiddleEdge, yMidOfMiddleEdge, p[3], p[4],
- myCircumcenter.x, myCircumcenter.y, false /*(isObtuse+1)%2*/);
- // make sure which point is the correct one to be considered
- if (isCorrect)
- {
- inter_x = p[3];
- inter_y = p[4];
- }
- else
- {
- inter_x = p[1];
- inter_y = p[2];
- }
- /// check if there is a Voronoi vertex between before intersection ///
- // check if the voronoi vertex is between the intersection and circumcenter
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y,
- neighborCircumcenter.x, neighborCircumcenter.y, ref voronoiOrInter);
- /// determine the point to be suggested ///
- if (p[0] > 0.0)
- { // there is at least one intersection point
- // if it is between circumcenter and intersection
- // if it returns 1.0 this means we have a voronoi vertex within feasible region
- if (Math.Abs(voronoiOrInter[0] - 1.0) <= EPS)
- {
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, neighborCircumcenter.x, neighborCircumcenter.y))
- {
- // go back to circumcenter
- dxSecondSuggestion = dx;
- dySecondSuggestion = dy;
- }
- else
- { // we are not creating a bad triangle
- // neighbor's circumcenter is suggested
- dxSecondSuggestion = voronoiOrInter[2] - torg.x;
- dySecondSuggestion = voronoiOrInter[3] - torg.y;
- }
- }
- else
- { // there is no voronoi vertex between intersection point and circumcenter
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
- {
- // if it is inside feasible region, then insert v2
- // apply perturbation
- // find the distance between circumcenter and intersection point
- d = Math.Sqrt((inter_x - myCircumcenter.x) * (inter_x - myCircumcenter.x) +
- (inter_y - myCircumcenter.y) * (inter_y - myCircumcenter.y));
- // then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.x - inter_x;
- ay = myCircumcenter.y - inter_y;
- ax = ax / d;
- ay = ay / d;
- // now calculate the new intersection point which is perturbated towards the circumcenter
- inter_x = inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
- inter_y = inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
- {
- // go back to circumcenter
- dxSecondSuggestion = dx;
- dySecondSuggestion = dy;
- }
- else
- {
- // intersection point is suggested
- dxSecondSuggestion = inter_x - torg.x;
- dySecondSuggestion = inter_y - torg.y;
- }
- }
- else
- {
- // intersection point is suggested
- dxSecondSuggestion = inter_x - torg.x;
- dySecondSuggestion = inter_y - torg.y;
- }
- }
- /// if it is an acute triangle, check if it is a good enough location ///
- // for acute triangle case, we need to check if it is ok to use either of them
- if ((smallestAngleCorner.x - myCircumcenter.x) * (smallestAngleCorner.x - myCircumcenter.x) +
- (smallestAngleCorner.y - myCircumcenter.y) * (smallestAngleCorner.y - myCircumcenter.y) >
- lengthConst * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y))))
- {
- // use circumcenter
- dxSecondSuggestion = dx;
- dySecondSuggestion = dy;
- }// else we stick on what we have found
- }
- }// if it is on the boundary, meaning no neighbor triangle in this direction, the other direction might be ok
- if (isObtuse)
- {
- //obtuse: do nothing
- dx = dxFirstSuggestion;
- dy = dyFirstSuggestion;
- }
- else
- { // acute : consider other direction
- if (justAcute * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y))) >
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)))
- {
- dx = dxSecondSuggestion;
- dy = dySecondSuggestion;
- }
- else
- {
- dx = dxFirstSuggestion;
- dy = dyFirstSuggestion;
- }
- }// end if obtuse
- }// end of relocation
- }// end of almostGood
- Point circumcenter = new Point();
- if (relocated <= 0)
- {
- circumcenter.x = torg.x + dx;
- circumcenter.y = torg.y + dy;
- }
- else
- {
- circumcenter.x = origin_x + dx;
- circumcenter.y = origin_y + dy;
- }
- xi = (yao * dx - xao * dy) * (2.0 * denominator);
- eta = (xdo * dy - ydo * dx) * (2.0 * denominator);
- return circumcenter;
- }
- /// <summary>
- /// Find a new location for a Steiner point.
- /// </summary>
- /// <param name="torg"></param>
- /// <param name="tdest"></param>
- /// <param name="tapex"></param>
- /// <param name="circumcenter"></param>
- /// <param name="xi"></param>
- /// <param name="eta"></param>
- /// <param name="offcenter"></param>
- /// <param name="badotri"></param>
- private Point FindNewLocation(Vertex torg, Vertex tdest, Vertex tapex,
- ref double xi, ref double eta, bool offcenter, Otri badotri)
- {
- double offconstant = behavior.offconstant;
- // for calculating the distances of the edges
- double xdo, ydo, xao, yao, xda, yda;
- double dodist, aodist, dadist;
- // for exact calculation
- double denominator;
- double dx, dy, dxoff, dyoff;
- ////////////////////////////// HALE'S VARIABLES //////////////////////////////
- // keeps the difference of coordinates edge
- double xShortestEdge = 0, yShortestEdge = 0;
- // keeps the square of edge lengths
- double shortestEdgeDist = 0, middleEdgeDist = 0, longestEdgeDist = 0;
- // keeps the vertices according to the angle incident to that vertex in a triangle
- Point smallestAngleCorner, middleAngleCorner, largestAngleCorner;
- // keeps the type of orientation if the triangle
- int orientation = 0;
- // keeps the coordinates of circumcenter of itself and neighbor triangle circumcenter
- Point myCircumcenter, neighborCircumcenter;
- // keeps if bad triangle is almost good or not
- int almostGood = 0;
- // keeps the cosine of the largest angle
- double cosMaxAngle;
- bool isObtuse; // 1: obtuse 0: nonobtuse
- // keeps the radius of petal
- double petalRadius;
- // for calculating petal center
- double xPetalCtr_1, yPetalCtr_1, xPetalCtr_2, yPetalCtr_2, xPetalCtr, yPetalCtr, xMidOfShortestEdge, yMidOfShortestEdge;
- double dxcenter1, dycenter1, dxcenter2, dycenter2;
- // for finding neighbor
- Otri neighborotri = default(Otri);
- double[] thirdPoint = new double[2];
- //int neighborNotFound = -1;
- // for keeping the vertices of the neighbor triangle
- Vertex neighborvertex_1;
- Vertex neighborvertex_2;
- Vertex neighborvertex_3;
- // dummy variables
- double xi_tmp = 0, eta_tmp = 0;
- //vertex thirdVertex;
- // for petal intersection
- double vector_x, vector_y, xMidOfLongestEdge, yMidOfLongestEdge, inter_x, inter_y;
- double[] p = new double[5], voronoiOrInter = new double[4];
- bool isCorrect;
- // for vector calculations in perturbation
- double ax, ay, d;
- double pertConst = 0.06; // perturbation constant
- double lengthConst = 1; // used at comparing circumcenter's distance to proposed point's distance
- double justAcute = 1; // used for making the program working for one direction only
- // for smoothing
- int relocated = 0;// used to differentiate between calling the deletevertex and just proposing a steiner point
- double[] newloc = new double[2]; // new location suggested by smoothing
- double origin_x = 0, origin_y = 0; // for keeping torg safe
- Otri delotri; // keeping the original orientation for relocation process
- // keeps the first and second direction suggested points
- double dxFirstSuggestion, dyFirstSuggestion, dxSecondSuggestion, dySecondSuggestion;
- // second direction variables
- double xMidOfMiddleEdge, yMidOfMiddleEdge;
- double minangle; // in order to make sure that the circumcircle of the bad triangle is greater than petal
- // for calculating the slab
- double linepnt1_x, linepnt1_y, linepnt2_x, linepnt2_y; // two points of the line
- double line_inter_x = 0, line_inter_y = 0;
- double line_vector_x, line_vector_y;
- double[] line_p = new double[3]; // used for getting the return values of functions related to line intersection
- double[] line_result = new double[4];
- // intersection of slab and the petal
- double petal_slab_inter_x_first, petal_slab_inter_y_first, petal_slab_inter_x_second, petal_slab_inter_y_second, x_1, y_1, x_2, y_2;
- double petal_bisector_x, petal_bisector_y, dist;
- double alpha;
- bool neighborNotFound_first;
- bool neighborNotFound_second;
- ////////////////////////////// END OF HALE'S VARIABLES //////////////////////////////
- Statistic.CircumcenterCount++;
- // Compute the circumcenter of the triangle.
- xdo = tdest.x - torg.x;
- ydo = tdest.y - torg.y;
- xao = tapex.x - torg.x;
- yao = tapex.y - torg.y;
- xda = tapex.x - tdest.x;
- yda = tapex.y - tdest.y;
- // keeps the square of the distances
- dodist = xdo * xdo + ydo * ydo;
- aodist = xao * xao + yao * yao;
- dadist = (tdest.x - tapex.x) * (tdest.x - tapex.x) +
- (tdest.y - tapex.y) * (tdest.y - tapex.y);
- // checking if the user wanted exact arithmetic or not
- if (Behavior.NoExact)
- {
- denominator = 0.5 / (xdo * yao - xao * ydo);
- }
- else
- {
- // Use the counterclockwise() routine to ensure a positive (and
- // reasonably accurate) result, avoiding any possibility of
- // division by zero.
- denominator = 0.5 / predicates.CounterClockwise(tdest, tapex, torg);
- // Don't count the above as an orientation test.
- Statistic.CounterClockwiseCount--;
- }
- // calculate the circumcenter in terms of distance to origin point
- dx = (yao * dodist - ydo * aodist) * denominator;
- dy = (xdo * aodist - xao * dodist) * denominator;
- // for debugging and for keeping circumcenter to use later
- // coordinate value of the circumcenter
- myCircumcenter = new Point(torg.x + dx, torg.y + dy);
- delotri = badotri; // save for later
- ///////////////// FINDING THE ORIENTATION OF TRIANGLE //////////////////
- // Find the (squared) length of the triangle's shortest edge. This
- // serves as a conservative estimate of the insertion radius of the
- // circumcenter's parent. The estimate is used to ensure that
- // the algorithm terminates even if very small angles appear in
- // the input PSLG.
- // find the orientation of the triangle, basically shortest and longest edges
- orientation = LongestShortestEdge(aodist, dadist, dodist);
- //printf("org: (%f,%f), dest: (%f,%f), apex: (%f,%f)\n",torg[0],torg[1],tdest[0],tdest[1],tapex[0],tapex[1]);
- /////////////////////////////////////////////////////////////////////////////////////////////
- // 123: shortest: aodist // 213: shortest: dadist // 312: shortest: dodist //
- // middle: dadist // middle: aodist // middle: aodist //
- // longest: dodist // longest: dodist // longest: dadist //
- // 132: shortest: aodist // 231: shortest: dadist // 321: shortest: dodist //
- // middle: dodist // middle: dodist // middle: dadist //
- // longest: dadist // longest: aodist // longest: aodist //
- /////////////////////////////////////////////////////////////////////////////////////////////
- switch (orientation)
- {
- case 123: // assign necessary information
- /// smallest angle corner: dest
- /// largest angle corner: apex
- xShortestEdge = xao; yShortestEdge = yao;
- shortestEdgeDist = aodist;
- middleEdgeDist = dadist;
- longestEdgeDist = dodist;
- smallestAngleCorner = tdest;
- middleAngleCorner = torg;
- largestAngleCorner = tapex;
- break;
- case 132: // assign necessary information
- /// smallest angle corner: dest
- /// largest angle corner: org
- xShortestEdge = xao; yShortestEdge = yao;
- shortestEdgeDist = aodist;
- middleEdgeDist = dodist;
- longestEdgeDist = dadist;
- smallestAngleCorner = tdest;
- middleAngleCorner = tapex;
- largestAngleCorner = torg;
- break;
- case 213: // assign necessary information
- /// smallest angle corner: org
- /// largest angle corner: apex
- xShortestEdge = xda; yShortestEdge = yda;
- shortestEdgeDist = dadist;
- middleEdgeDist = aodist;
- longestEdgeDist = dodist;
- smallestAngleCorner = torg;
- middleAngleCorner = tdest;
- largestAngleCorner = tapex;
- break;
- case 231: // assign necessary information
- /// smallest angle corner: org
- /// largest angle corner: dest
- xShortestEdge = xda; yShortestEdge = yda;
- shortestEdgeDist = dadist;
- middleEdgeDist = dodist;
- longestEdgeDist = aodist;
- smallestAngleCorner = torg;
- middleAngleCorner = tapex;
- largestAngleCorner = tdest;
- break;
- case 312: // assign necessary information
- /// smallest angle corner: apex
- /// largest angle corner: org
- xShortestEdge = xdo; yShortestEdge = ydo;
- shortestEdgeDist = dodist;
- middleEdgeDist = aodist;
- longestEdgeDist = dadist;
- smallestAngleCorner = tapex;
- middleAngleCorner = tdest;
- largestAngleCorner = torg;
- break;
- case 321: // assign necessary information
- default: // TODO: is this safe?
- /// smallest angle corner: apex
- /// largest angle corner: dest
- xShortestEdge = xdo; yShortestEdge = ydo;
- shortestEdgeDist = dodist;
- middleEdgeDist = dadist;
- longestEdgeDist = aodist;
- smallestAngleCorner = tapex;
- middleAngleCorner = torg;
- largestAngleCorner = tdest;
- break;
- }// end of switch
- // check for offcenter condition
- if (offcenter && (offconstant > 0.0))
- {
- // origin has the smallest angle
- if (orientation == 213 || orientation == 231)
- {
- // Find the position of the off-center, as described by Alper Ungor.
- dxoff = 0.5 * xShortestEdge - offconstant * yShortestEdge;
- dyoff = 0.5 * yShortestEdge + offconstant * xShortestEdge;
- // If the off-center is closer to destination than the
- // circumcenter, use the off-center instead.
- /// doubleLY BAD CASE ///
- if (dxoff * dxoff + dyoff * dyoff <
- (dx - xdo) * (dx - xdo) + (dy - ydo) * (dy - ydo))
- {
- dx = xdo + dxoff;
- dy = ydo + dyoff;
- }
- /// ALMOST GOOD CASE ///
- else
- {
- almostGood = 1;
- }
- // destination has the smallest angle
- }
- else if (orientation == 123 || orientation == 132)
- {
- // Find the position of the off-center, as described by Alper Ungor.
- dxoff = 0.5 * xShortestEdge + offconstant * yShortestEdge;
- dyoff = 0.5 * yShortestEdge - offconstant * xShortestEdge;
- // If the off-center is closer to the origin than the
- // circumcenter, use the off-center instead.
- /// doubleLY BAD CASE ///
- if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy)
- {
- dx = dxoff;
- dy = dyoff;
- }
- /// ALMOST GOOD CASE ///
- else
- {
- almostGood = 1;
- }
- // apex has the smallest angle
- }
- else
- {//orientation == 312 || orientation == 321
- // Find the position of the off-center, as described by Alper Ungor.
- dxoff = 0.5 * xShortestEdge - offconstant * yShortestEdge;
- dyoff = 0.5 * yShortestEdge + offconstant * xShortestEdge;
- // If the off-center is closer to the origin than the
- // circumcenter, use the off-center instead.
- /// doubleLY BAD CASE ///
- if (dxoff * dxoff + dyoff * dyoff < dx * dx + dy * dy)
- {
- dx = dxoff;
- dy = dyoff;
- }
- /// ALMOST GOOD CASE ///
- else
- {
- almostGood = 1;
- }
- }
- }
- // if the bad triangle is almost good, apply our approach
- if (almostGood == 1)
- {
- /// calculate cosine of largest angle ///
- cosMaxAngle = (middleEdgeDist + shortestEdgeDist - longestEdgeDist) / (2 * Math.Sqrt(middleEdgeDist) * Math.Sqrt(shortestEdgeDist));
- if (cosMaxAngle < 0.0)
- {
- // obtuse
- isObtuse = true;
- }
- else if (Math.Abs(cosMaxAngle - 0.0) <= EPS)
- {
- // right triangle (largest angle is 90 degrees)
- isObtuse = true;
- }
- else
- {
- // nonobtuse
- isObtuse = false;
- }
- /// RELOCATION (LOCAL SMOOTHING) ///
- /// check for possible relocation of one of triangle's points ///
- relocated = DoSmoothing(delotri, torg, tdest, tapex, ref newloc);
- /// if relocation is possible, delete that vertex and insert a vertex at the new location ///
- if (relocated > 0)
- {
- Statistic.RelocationCount++;
- dx = newloc[0] - torg.x;
- dy = newloc[1] - torg.y;
- origin_x = torg.x; // keep for later use
- origin_y = torg.y;
- switch (relocated)
- {
- case 1:
- //printf("Relocate: (%f,%f)\n", torg[0],torg[1]);
- mesh.DeleteVertex(ref delotri);
- break;
- case 2:
- //printf("Relocate: (%f,%f)\n", tdest[0],tdest[1]);
- delotri.Lnext();
- mesh.DeleteVertex(ref delotri);
- break;
- case 3:
- //printf("Relocate: (%f,%f)\n", tapex[0],tapex[1]);
- delotri.Lprev();
- mesh.DeleteVertex(ref delotri);
- break;
- }
- }
- else
- {
- // calculate radius of the petal according to angle constraint
- // first find the visible region, PETAL
- // find the center of the circle and radius
- // choose minimum angle as the maximum of quality angle and the minimum angle of the bad triangle
- minangle = Math.Acos((middleEdgeDist + longestEdgeDist - shortestEdgeDist) / (2 * Math.Sqrt(middleEdgeDist) * Math.Sqrt(longestEdgeDist))) * 180.0 / Math.PI;
- if (behavior.MinAngle > minangle)
- {
- minangle = behavior.MinAngle;
- }
- else
- {
- minangle = minangle + 0.5;
- }
- petalRadius = Math.Sqrt(shortestEdgeDist) / (2 * Math.Sin(minangle * Math.PI / 180.0));
- /// compute two possible centers of the petal ///
- // finding the center
- // first find the middle point of smallest edge
- xMidOfShortestEdge = (middleAngleCorner.x + largestAngleCorner.x) / 2.0;
- yMidOfShortestEdge = (middleAngleCorner.y + largestAngleCorner.y) / 2.0;
- // two possible centers
- xPetalCtr_1 = xMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.y -
- largestAngleCorner.y) / Math.Sqrt(shortestEdgeDist);
- yPetalCtr_1 = yMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.x -
- middleAngleCorner.x) / Math.Sqrt(shortestEdgeDist);
- xPetalCtr_2 = xMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.y -
- largestAngleCorner.y) / Math.Sqrt(shortestEdgeDist);
- yPetalCtr_2 = yMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.x -
- middleAngleCorner.x) / Math.Sqrt(shortestEdgeDist);
- // find the correct circle since there will be two possible circles
- // calculate the distance to smallest angle corner
- dxcenter1 = (xPetalCtr_1 - smallestAngleCorner.x) * (xPetalCtr_1 - smallestAngleCorner.x);
- dycenter1 = (yPetalCtr_1 - smallestAngleCorner.y) * (yPetalCtr_1 - smallestAngleCorner.y);
- dxcenter2 = (xPetalCtr_2 - smallestAngleCorner.x) * (xPetalCtr_2 - smallestAngleCorner.x);
- dycenter2 = (yPetalCtr_2 - smallestAngleCorner.y) * (yPetalCtr_2 - smallestAngleCorner.y);
- // whichever is closer to smallest angle corner, it must be the center
- if (dxcenter1 + dycenter1 <= dxcenter2 + dycenter2)
- {
- xPetalCtr = xPetalCtr_1; yPetalCtr = yPetalCtr_1;
- }
- else
- {
- xPetalCtr = xPetalCtr_2; yPetalCtr = yPetalCtr_2;
- }
- /// find the third point of the neighbor triangle ///
- neighborNotFound_first = GetNeighborsVertex(badotri, middleAngleCorner.x, middleAngleCorner.y,
- smallestAngleCorner.x, smallestAngleCorner.y, ref thirdPoint, ref neighborotri);
- /// find the circumcenter of the neighbor triangle ///
- dxFirstSuggestion = dx; // if we cannot find any appropriate suggestion, we use circumcenter
- dyFirstSuggestion = dy;
- /// before checking the neighbor, find the petal and slab intersections ///
- // calculate the intersection point of the petal and the slab lines
- // first find the vector
- // distance between xmid and petal center
- dist = Math.Sqrt((xPetalCtr - xMidOfShortestEdge) * (xPetalCtr - xMidOfShortestEdge) + (yPetalCtr - yMidOfShortestEdge) * (yPetalCtr - yMidOfShortestEdge));
- // find the unit vector goes from mid point to petal center
- line_vector_x = (xPetalCtr - xMidOfShortestEdge) / dist;
- line_vector_y = (yPetalCtr - yMidOfShortestEdge) / dist;
- // find the third point other than p and q
- petal_bisector_x = xPetalCtr + line_vector_x * petalRadius;
- petal_bisector_y = yPetalCtr + line_vector_y * petalRadius;
- alpha = (2.0 * behavior.MaxAngle + minangle - 180.0) * Math.PI / 180.0;
- // rotate the vector cw around the petal center
- x_1 = petal_bisector_x * Math.Cos(alpha) + petal_bisector_y * Math.Sin(alpha) + xPetalCtr - xPetalCtr * Math.Cos(alpha) - yPetalCtr * Math.Sin(alpha);
- y_1 = -petal_bisector_x * Math.Sin(alpha) + petal_bisector_y * Math.Cos(alpha) + yPetalCtr + xPetalCtr * Math.Sin(alpha) - yPetalCtr * Math.Cos(alpha);
- // rotate the vector ccw around the petal center
- x_2 = petal_bisector_x * Math.Cos(alpha) - petal_bisector_y * Math.Sin(alpha) + xPetalCtr - xPetalCtr * Math.Cos(alpha) + yPetalCtr * Math.Sin(alpha);
- y_2 = petal_bisector_x * Math.Sin(alpha) + petal_bisector_y * Math.Cos(alpha) + yPetalCtr - xPetalCtr * Math.Sin(alpha) - yPetalCtr * Math.Cos(alpha);
- // we need to find correct intersection point, since there are two possibilities
- // weather it is obtuse/acute the one closer to the minimum angle corner is the first direction
- isCorrect = ChooseCorrectPoint(x_2, y_2, middleAngleCorner.x, middleAngleCorner.y, x_1, y_1, true);
- // make sure which point is the correct one to be considered
- if (isCorrect)
- {
- petal_slab_inter_x_first = x_1;
- petal_slab_inter_y_first = y_1;
- petal_slab_inter_x_second = x_2;
- petal_slab_inter_y_second = y_2;
- }
- else
- {
- petal_slab_inter_x_first = x_2;
- petal_slab_inter_y_first = y_2;
- petal_slab_inter_x_second = x_1;
- petal_slab_inter_y_second = y_1;
- }
- /// choose the correct intersection point ///
- // calculate middle point of the longest edge(bisector)
- xMidOfLongestEdge = (middleAngleCorner.x + smallestAngleCorner.x) / 2.0;
- yMidOfLongestEdge = (middleAngleCorner.y + smallestAngleCorner.y) / 2.0;
- // if there is a neighbor triangle
- if (!neighborNotFound_first)
- {
- neighborvertex_1 = neighborotri.Org();
- neighborvertex_2 = neighborotri.Dest();
- neighborvertex_3 = neighborotri.Apex();
- // now calculate neighbor's circumcenter which is the voronoi site
- neighborCircumcenter = predicates.FindCircumcenter(neighborvertex_1, neighborvertex_2, neighborvertex_3,
- ref xi_tmp, ref eta_tmp);
- /// compute petal and Voronoi edge intersection ///
- // in order to avoid degenerate cases, we need to do a vector based calculation for line
- vector_x = (middleAngleCorner.y - smallestAngleCorner.y);//(-y, x)
- vector_y = smallestAngleCorner.x - middleAngleCorner.x;
- vector_x = myCircumcenter.x + vector_x;
- vector_y = myCircumcenter.y + vector_y;
- // by intersecting bisectors you will end up with the one you want to walk on
- // then this line and circle should be intersected
- CircleLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y,
- xPetalCtr, yPetalCtr, petalRadius, ref p);
- // we need to find correct intersection point, since line intersects circle twice
- isCorrect = ChooseCorrectPoint(xMidOfLongestEdge, yMidOfLongestEdge, p[3], p[4],
- myCircumcenter.x, myCircumcenter.y, isObtuse);
- // make sure which point is the correct one to be considered
- if (isCorrect)
- {
- inter_x = p[3];
- inter_y = p[4];
- }
- else
- {
- inter_x = p[1];
- inter_y = p[2];
- }
- //----------------------hale new first direction: for slab calculation---------------//
- // calculate the intersection of angle lines and Voronoi
- linepnt1_x = middleAngleCorner.x;
- linepnt1_y = middleAngleCorner.y;
- // vector from middleAngleCorner to largestAngleCorner
- line_vector_x = largestAngleCorner.x - middleAngleCorner.x;
- line_vector_y = largestAngleCorner.y - middleAngleCorner.y;
- // rotate the vector around middleAngleCorner in cw by maxangle degrees
- linepnt2_x = petal_slab_inter_x_first;
- linepnt2_y = petal_slab_inter_y_first;
- // now calculate the intersection of two lines
- LineLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y, linepnt1_x, linepnt1_y, linepnt2_x, linepnt2_y, ref line_p);
- // check if there is a suitable intersection
- if (line_p[0] > 0.0)
- {
- line_inter_x = line_p[1];
- line_inter_y = line_p[2];
- }
- else
- {
- // for debugging (to make sure)
- //printf("1) No intersection between two lines!!!\n");
- //printf("(%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f)\n",myCircumcenter.x,myCircumcenter.y,vector_x,vector_y,linepnt1_x,linepnt1_y,linepnt2_x,linepnt2_y);
- }
- //---------------------------------------------------------------------//
- /// check if there is a Voronoi vertex between before intersection ///
- // check if the voronoi vertex is between the intersection and circumcenter
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y,
- neighborCircumcenter.x, neighborCircumcenter.y, ref voronoiOrInter);
- /// determine the point to be suggested ///
- if (p[0] > 0.0)
- { // there is at least one intersection point
- // if it is between circumcenter and intersection
- // if it returns 1.0 this means we have a voronoi vertex within feasible region
- if (Math.Abs(voronoiOrInter[0] - 1.0) <= EPS)
- {
- //-----------------hale new continues 1------------------//
- // now check if the line intersection is between cc and voronoi
- PointBetweenPoints(voronoiOrInter[2], voronoiOrInter[3], myCircumcenter.x, myCircumcenter.y, line_inter_x, line_inter_y, ref line_result);
- if (Math.Abs(line_result[0] - 1.0) <= EPS && line_p[0] > 0.0)
- {
- // check if we can go further by picking the slab line and petal intersection
- // calculate the distance to the smallest angle corner
- // check if we create a bad triangle or not
- if (((smallestAngleCorner.x - petal_slab_inter_x_first) * (smallestAngleCorner.x - petal_slab_inter_x_first) +
- (smallestAngleCorner.y - petal_slab_inter_y_first) * (smallestAngleCorner.y - petal_slab_inter_y_first) >
- lengthConst * ((smallestAngleCorner.x - line_inter_x) *
- (smallestAngleCorner.x - line_inter_x) +
- (smallestAngleCorner.y - line_inter_y) *
- (smallestAngleCorner.y - line_inter_y)))
- && (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, petal_slab_inter_x_first, petal_slab_inter_y_first))
- && MinDistanceToNeighbor(petal_slab_inter_x_first, petal_slab_inter_y_first, ref neighborotri) > MinDistanceToNeighbor(line_inter_x, line_inter_y, ref neighborotri))
- {
- // check the neighbor's vertices also, which one if better
- //slab and petal intersection is advised
- dxFirstSuggestion = petal_slab_inter_x_first - torg.x;
- dyFirstSuggestion = petal_slab_inter_y_first - torg.y;
- }
- else
- { // slab intersection point is further away
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
- {
- // apply perturbation
- // find the distance between circumcenter and intersection point
- d = Math.Sqrt((line_inter_x - myCircumcenter.x) * (line_inter_x - myCircumcenter.x) +
- (line_inter_y - myCircumcenter.y) * (line_inter_y - myCircumcenter.y));
- // then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.x - line_inter_x;
- ay = myCircumcenter.y - line_inter_y;
- ax = ax / d;
- ay = ay / d;
- // now calculate the new intersection point which is perturbated towards the circumcenter
- line_inter_x = line_inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
- line_inter_y = line_inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
- {
- // go back to circumcenter
- dxFirstSuggestion = dx;
- dyFirstSuggestion = dy;
- }
- else
- {
- // intersection point is suggested
- dxFirstSuggestion = line_inter_x - torg.x;
- dyFirstSuggestion = line_inter_y - torg.y;
- }
- }
- else
- {// we are not creating a bad triangle
- // slab intersection is advised
- dxFirstSuggestion = line_result[2] - torg.x;
- dyFirstSuggestion = line_result[3] - torg.y;
- }
- }
- //------------------------------------------------------//
- }
- else
- {
- /// NOW APPLY A BREADTH-FIRST SEARCH ON THE VORONOI
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, neighborCircumcenter.x, neighborCircumcenter.y))
- {
- // go back to circumcenter
- dxFirstSuggestion = dx;
- dyFirstSuggestion = dy;
- }
- else
- {
- // we are not creating a bad triangle
- // neighbor's circumcenter is suggested
- dxFirstSuggestion = voronoiOrInter[2] - torg.x;
- dyFirstSuggestion = voronoiOrInter[3] - torg.y;
- }
- }
- }
- else
- { // there is no voronoi vertex between intersection point and circumcenter
- //-----------------hale new continues 2-----------------//
- // now check if the line intersection is between cc and intersection point
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y, line_inter_x, line_inter_y, ref line_result);
- if (Math.Abs(line_result[0] - 1.0) <= EPS && line_p[0] > 0.0)
- {
- // check if we can go further by picking the slab line and petal intersection
- // calculate the distance to the smallest angle corner
- if (((smallestAngleCorner.x - petal_slab_inter_x_first) * (smallestAngleCorner.x - petal_slab_inter_x_first) +
- (smallestAngleCorner.y - petal_slab_inter_y_first) * (smallestAngleCorner.y - petal_slab_inter_y_first) >
- lengthConst * ((smallestAngleCorner.x - line_inter_x) *
- (smallestAngleCorner.x - line_inter_x) +
- (smallestAngleCorner.y - line_inter_y) *
- (smallestAngleCorner.y - line_inter_y)))
- && (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, petal_slab_inter_x_first, petal_slab_inter_y_first))
- && MinDistanceToNeighbor(petal_slab_inter_x_first, petal_slab_inter_y_first, ref neighborotri) > MinDistanceToNeighbor(line_inter_x, line_inter_y, ref neighborotri))
- {
- //slab and petal intersection is advised
- dxFirstSuggestion = petal_slab_inter_x_first - torg.x;
- dyFirstSuggestion = petal_slab_inter_y_first - torg.y;
- }
- else
- { // slab intersection point is further away
- if (IsBadTriangleAngle(largestAngleCorner.x, largestAngleCorner.y, middleAngleCorner.x, middleAngleCorner.y, line_inter_x, line_inter_y))
- {
- // apply perturbation
- // find the distance between circumcenter and intersection point
- d = Math.Sqrt((line_inter_x - myCircumcenter.x) * (line_inter_x - myCircumcenter.x) +
- (line_inter_y - myCircumcenter.y) * (line_inter_y - myCircumcenter.y));
- // then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.x - line_inter_x;
- ay = myCircumcenter.y - line_inter_y;
- ax = ax / d;
- ay = ay / d;
- // now calculate the new intersection point which is perturbated towards the circumcenter
- line_inter_x = line_inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
- line_inter_y = line_inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
- {
- // go back to circumcenter
- dxFirstSuggestion = dx;
- dyFirstSuggestion = dy;
- }
- else
- {
- // intersection point is suggested
- dxFirstSuggestion = line_inter_x - torg.x;
- dyFirstSuggestion = line_inter_y - torg.y;
- }
- }
- else
- {// we are not creating a bad triangle
- // slab intersection is advised
- dxFirstSuggestion = line_result[2] - torg.x;
- dyFirstSuggestion = line_result[3] - torg.y;
- }
- }
- //------------------------------------------------------//
- }
- else
- {
- if (IsBadTriangleAngle(largestAngleCorner.x, largestAngleCorner.y, middleAngleCorner.x, middleAngleCorner.y, inter_x, inter_y))
- {
- //printf("testtriangle returned false! bad triangle\n");
- // if it is inside feasible region, then insert v2
- // apply perturbation
- // find the distance between circumcenter and intersection point
- d = Math.Sqrt((inter_x - myCircumcenter.x) * (inter_x - myCircumcenter.x) +
- (inter_y - myCircumcenter.y) * (inter_y - myCircumcenter.y));
- // then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.x - inter_x;
- ay = myCircumcenter.y - inter_y;
- ax = ax / d;
- ay = ay / d;
- // now calculate the new intersection point which is perturbated towards the circumcenter
- inter_x = inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
- inter_y = inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
- {
- // go back to circumcenter
- dxFirstSuggestion = dx;
- dyFirstSuggestion = dy;
- }
- else
- {
- // intersection point is suggested
- dxFirstSuggestion = inter_x - torg.x;
- dyFirstSuggestion = inter_y - torg.y;
- }
- }
- else
- {
- // intersection point is suggested
- dxFirstSuggestion = inter_x - torg.x;
- dyFirstSuggestion = inter_y - torg.y;
- }
- }
- }
- /// if it is an acute triangle, check if it is a good enough location ///
- // for acute triangle case, we need to check if it is ok to use either of them
- if ((smallestAngleCorner.x - myCircumcenter.x) * (smallestAngleCorner.x - myCircumcenter.x) +
- (smallestAngleCorner.y - myCircumcenter.y) * (smallestAngleCorner.y - myCircumcenter.y) >
- lengthConst * ((smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y))))
- {
- // use circumcenter
- dxFirstSuggestion = dx;
- dyFirstSuggestion = dy;
- }// else we stick to what we have found
- }// intersection point
- }// if it is on the boundary, meaning no neighbor triangle in this direction, try other direction
- /// DO THE SAME THING FOR THE OTHER DIRECTION ///
- /// find the third point of the neighbor triangle ///
- neighborNotFound_second = GetNeighborsVertex(badotri, largestAngleCorner.x, largestAngleCorner.y,
- smallestAngleCorner.x, smallestAngleCorner.y, ref thirdPoint, ref neighborotri);
- /// find the circumcenter of the neighbor triangle ///
- dxSecondSuggestion = dx; // if we cannot find any appropriate suggestion, we use circumcenter
- dySecondSuggestion = dy;
- /// choose the correct intersection point ///
- // calculate middle point of the longest edge(bisector)
- xMidOfMiddleEdge = (largestAngleCorner.x + smallestAngleCorner.x) / 2.0;
- yMidOfMiddleEdge = (largestAngleCorner.y + smallestAngleCorner.y) / 2.0;
- // if there is a neighbor triangle
- if (!neighborNotFound_second)
- {
- neighborvertex_1 = neighborotri.Org();
- neighborvertex_2 = neighborotri.Dest();
- neighborvertex_3 = neighborotri.Apex();
- // now calculate neighbor's circumcenter which is the voronoi site
- neighborCircumcenter = predicates.FindCircumcenter(neighborvertex_1, neighborvertex_2, neighborvertex_3,
- ref xi_tmp, ref eta_tmp);
- /// compute petal and Voronoi edge intersection ///
- // in order to avoid degenerate cases, we need to do a vector based calculation for line
- vector_x = (largestAngleCorner.y - smallestAngleCorner.y);//(-y, x)
- vector_y = smallestAngleCorner.x - largestAngleCorner.x;
- vector_x = myCircumcenter.x + vector_x;
- vector_y = myCircumcenter.y + vector_y;
- // by intersecting bisectors you will end up with the one you want to walk on
- // then this line and circle should be intersected
- CircleLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y,
- xPetalCtr, yPetalCtr, petalRadius, ref p);
- // we need to find correct intersection point, since line intersects circle twice
- // this direction is always ACUTE
- isCorrect = ChooseCorrectPoint(xMidOfMiddleEdge, yMidOfMiddleEdge, p[3], p[4],
- myCircumcenter.x, myCircumcenter.y, false /*(isObtuse+1)%2*/);
- // make sure which point is the correct one to be considered
- if (isCorrect)
- {
- inter_x = p[3];
- inter_y = p[4];
- }
- else
- {
- inter_x = p[1];
- inter_y = p[2];
- }
- //----------------------hale new second direction:for slab calculation---------------//
- // calculate the intersection of angle lines and Voronoi
- linepnt1_x = largestAngleCorner.x;
- linepnt1_y = largestAngleCorner.y;
- // vector from largestAngleCorner to middleAngleCorner
- line_vector_x = middleAngleCorner.x - largestAngleCorner.x;
- line_vector_y = middleAngleCorner.y - largestAngleCorner.y;
- // rotate the vector around largestAngleCorner in ccw by maxangle degrees
- linepnt2_x = petal_slab_inter_x_second;
- linepnt2_y = petal_slab_inter_y_second;
- // now calculate the intersection of two lines
- LineLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y, linepnt1_x, linepnt1_y, linepnt2_x, linepnt2_y, ref line_p);
- // check if there is a suitable intersection
- if (line_p[0] > 0.0)
- {
- line_inter_x = line_p[1];
- line_inter_y = line_p[2];
- }
- else
- {
- // for debugging (to make sure)
- //printf("1) No intersection between two lines!!!\n");
- //printf("(%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f)\n",myCircumcenter.x,myCircumcenter.y,vector_x,vector_y,linepnt1_x,linepnt1_y,linepnt2_x,linepnt2_y);
- }
- //---------------------------------------------------------------------//
- /// check if there is a Voronoi vertex between before intersection ///
- // check if the voronoi vertex is between the intersection and circumcenter
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y,
- neighborCircumcenter.x, neighborCircumcenter.y, ref voronoiOrInter);
- /// determine the point to be suggested ///
- if (p[0] > 0.0)
- { // there is at least one intersection point
- // if it is between circumcenter and intersection
- // if it returns 1.0 this means we have a voronoi vertex within feasible region
- if (Math.Abs(voronoiOrInter[0] - 1.0) <= EPS)
- {
- //-----------------hale new continues 1------------------//
- // now check if the line intersection is between cc and voronoi
- PointBetweenPoints(voronoiOrInter[2], voronoiOrInter[3], myCircumcenter.x, myCircumcenter.y, line_inter_x, line_inter_y, ref line_result);
- if (Math.Abs(line_result[0] - 1.0) <= EPS && line_p[0] > 0.0)
- {
- // check if we can go further by picking the slab line and petal intersection
- // calculate the distance to the smallest angle corner
- //
- if (((smallestAngleCorner.x - petal_slab_inter_x_second) * (smallestAngleCorner.x - petal_slab_inter_x_second) +
- (smallestAngleCorner.y - petal_slab_inter_y_second) * (smallestAngleCorner.y - petal_slab_inter_y_second) >
- lengthConst * ((smallestAngleCorner.x - line_inter_x) *
- (smallestAngleCorner.x - line_inter_x) +
- (smallestAngleCorner.y - line_inter_y) *
- (smallestAngleCorner.y - line_inter_y)))
- && (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, petal_slab_inter_x_second, petal_slab_inter_y_second))
- && MinDistanceToNeighbor(petal_slab_inter_x_second, petal_slab_inter_y_second, ref neighborotri) > MinDistanceToNeighbor(line_inter_x, line_inter_y, ref neighborotri))
- {
- // slab and petal intersection is advised
- dxSecondSuggestion = petal_slab_inter_x_second - torg.x;
- dySecondSuggestion = petal_slab_inter_y_second - torg.y;
- }
- else
- { // slab intersection point is further away
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
- {
- // apply perturbation
- // find the distance between circumcenter and intersection point
- d = Math.Sqrt((line_inter_x - myCircumcenter.x) * (line_inter_x - myCircumcenter.x) +
- (line_inter_y - myCircumcenter.y) * (line_inter_y - myCircumcenter.y));
- // then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.x - line_inter_x;
- ay = myCircumcenter.y - line_inter_y;
- ax = ax / d;
- ay = ay / d;
- // now calculate the new intersection point which is perturbated towards the circumcenter
- line_inter_x = line_inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
- line_inter_y = line_inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
- {
- // go back to circumcenter
- dxSecondSuggestion = dx;
- dySecondSuggestion = dy;
- }
- else
- {
- // intersection point is suggested
- dxSecondSuggestion = line_inter_x - torg.x;
- dySecondSuggestion = line_inter_y - torg.y;
- }
- }
- else
- {// we are not creating a bad triangle
- // slab intersection is advised
- dxSecondSuggestion = line_result[2] - torg.x;
- dySecondSuggestion = line_result[3] - torg.y;
- }
- }
- //------------------------------------------------------//
- }
- else
- {
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, neighborCircumcenter.x, neighborCircumcenter.y))
- {
- // go back to circumcenter
- dxSecondSuggestion = dx;
- dySecondSuggestion = dy;
- }
- else
- { // we are not creating a bad triangle
- // neighbor's circumcenter is suggested
- dxSecondSuggestion = voronoiOrInter[2] - torg.x;
- dySecondSuggestion = voronoiOrInter[3] - torg.y;
- }
- }
- }
- else
- { // there is no voronoi vertex between intersection point and circumcenter
- //-----------------hale new continues 2-----------------//
- // now check if the line intersection is between cc and intersection point
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y, line_inter_x, line_inter_y, ref line_result);
- if (Math.Abs(line_result[0] - 1.0) <= EPS && line_p[0] > 0.0)
- {
- // check if we can go further by picking the slab line and petal intersection
- // calculate the distance to the smallest angle corner
- if (((smallestAngleCorner.x - petal_slab_inter_x_second) * (smallestAngleCorner.x - petal_slab_inter_x_second) +
- (smallestAngleCorner.y - petal_slab_inter_y_second) * (smallestAngleCorner.y - petal_slab_inter_y_second) >
- lengthConst * ((smallestAngleCorner.x - line_inter_x) *
- (smallestAngleCorner.x - line_inter_x) +
- (smallestAngleCorner.y - line_inter_y) *
- (smallestAngleCorner.y - line_inter_y)))
- && (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, petal_slab_inter_x_second, petal_slab_inter_y_second))
- && MinDistanceToNeighbor(petal_slab_inter_x_second, petal_slab_inter_y_second, ref neighborotri) > MinDistanceToNeighbor(line_inter_x, line_inter_y, ref neighborotri))
- {
- // slab and petal intersection is advised
- dxSecondSuggestion = petal_slab_inter_x_second - torg.x;
- dySecondSuggestion = petal_slab_inter_y_second - torg.y;
- }
- else
- { // slab intersection point is further away ;
- if (IsBadTriangleAngle(largestAngleCorner.x, largestAngleCorner.y, middleAngleCorner.x, middleAngleCorner.y, line_inter_x, line_inter_y))
- {
- // apply perturbation
- // find the distance between circumcenter and intersection point
- d = Math.Sqrt((line_inter_x - myCircumcenter.x) * (line_inter_x - myCircumcenter.x) +
- (line_inter_y - myCircumcenter.y) * (line_inter_y - myCircumcenter.y));
- // then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.x - line_inter_x;
- ay = myCircumcenter.y - line_inter_y;
- ax = ax / d;
- ay = ay / d;
- // now calculate the new intersection point which is perturbated towards the circumcenter
- line_inter_x = line_inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
- line_inter_y = line_inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
- {
- // go back to circumcenter
- dxSecondSuggestion = dx;
- dySecondSuggestion = dy;
- }
- else
- {
- // intersection point is suggested
- dxSecondSuggestion = line_inter_x - torg.x;
- dySecondSuggestion = line_inter_y - torg.y;
- }
- }
- else
- {
- // we are not creating a bad triangle
- // slab intersection is advised
- dxSecondSuggestion = line_result[2] - torg.x;
- dySecondSuggestion = line_result[3] - torg.y;
- }
- }
- //------------------------------------------------------//
- }
- else
- {
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
- {
- // if it is inside feasible region, then insert v2
- // apply perturbation
- // find the distance between circumcenter and intersection point
- d = Math.Sqrt((inter_x - myCircumcenter.x) * (inter_x - myCircumcenter.x) +
- (inter_y - myCircumcenter.y) * (inter_y - myCircumcenter.y));
- // then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.x - inter_x;
- ay = myCircumcenter.y - inter_y;
- ax = ax / d;
- ay = ay / d;
- // now calculate the new intersection point which is perturbated towards the circumcenter
- inter_x = inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
- inter_y = inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
- {
- // go back to circumcenter
- dxSecondSuggestion = dx;
- dySecondSuggestion = dy;
- }
- else
- {
- // intersection point is suggested
- dxSecondSuggestion = inter_x - torg.x;
- dySecondSuggestion = inter_y - torg.y;
- }
- }
- else
- {
- // intersection point is suggested
- dxSecondSuggestion = inter_x - torg.x;
- dySecondSuggestion = inter_y - torg.y;
- }
- }
- }
- /// if it is an acute triangle, check if it is a good enough location ///
- // for acute triangle case, we need to check if it is ok to use either of them
- if ((smallestAngleCorner.x - myCircumcenter.x) * (smallestAngleCorner.x - myCircumcenter.x) +
- (smallestAngleCorner.y - myCircumcenter.y) * (smallestAngleCorner.y - myCircumcenter.y) >
- lengthConst * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y))))
- {
- // use circumcenter
- dxSecondSuggestion = dx;
- dySecondSuggestion = dy;
- }// else we stick on what we have found
- }
- }// if it is on the boundary, meaning no neighbor triangle in this direction, the other direction might be ok
- if (isObtuse)
- {
- if (neighborNotFound_first && neighborNotFound_second)
- {
- //obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.x - (xMidOfMiddleEdge)) *
- (smallestAngleCorner.x - (xMidOfMiddleEdge)) +
- (smallestAngleCorner.y - (yMidOfMiddleEdge)) *
- (smallestAngleCorner.y - (yMidOfMiddleEdge))) >
- (smallestAngleCorner.x - (xMidOfLongestEdge)) *
- (smallestAngleCorner.x - (xMidOfLongestEdge)) +
- (smallestAngleCorner.y - (yMidOfLongestEdge)) *
- (smallestAngleCorner.y - (yMidOfLongestEdge)))
- {
- dx = dxSecondSuggestion;
- dy = dySecondSuggestion;
- }
- else
- {
- dx = dxFirstSuggestion;
- dy = dyFirstSuggestion;
- }
- }
- else if (neighborNotFound_first)
- {
- //obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y))) >
- (smallestAngleCorner.x - (xMidOfLongestEdge)) *
- (smallestAngleCorner.x - (xMidOfLongestEdge)) +
- (smallestAngleCorner.y - (yMidOfLongestEdge)) *
- (smallestAngleCorner.y - (yMidOfLongestEdge)))
- {
- dx = dxSecondSuggestion;
- dy = dySecondSuggestion;
- }
- else
- {
- dx = dxFirstSuggestion;
- dy = dyFirstSuggestion;
- }
- }
- else if (neighborNotFound_second)
- {
- //obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.x - (xMidOfMiddleEdge)) *
- (smallestAngleCorner.x - (xMidOfMiddleEdge)) +
- (smallestAngleCorner.y - (yMidOfMiddleEdge)) *
- (smallestAngleCorner.y - (yMidOfMiddleEdge))) >
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)))
- {
- dx = dxSecondSuggestion;
- dy = dySecondSuggestion;
- }
- else
- {
- dx = dxFirstSuggestion;
- dy = dyFirstSuggestion;
- }
- }
- else
- {
- //obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y))) >
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)))
- {
- dx = dxSecondSuggestion;
- dy = dySecondSuggestion;
- }
- else
- {
- dx = dxFirstSuggestion;
- dy = dyFirstSuggestion;
- }
- }
- }
- else
- { // acute : consider other direction
- if (neighborNotFound_first && neighborNotFound_second)
- {
- //obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.x - (xMidOfMiddleEdge)) *
- (smallestAngleCorner.x - (xMidOfMiddleEdge)) +
- (smallestAngleCorner.y - (yMidOfMiddleEdge)) *
- (smallestAngleCorner.y - (yMidOfMiddleEdge))) >
- (smallestAngleCorner.x - (xMidOfLongestEdge)) *
- (smallestAngleCorner.x - (xMidOfLongestEdge)) +
- (smallestAngleCorner.y - (yMidOfLongestEdge)) *
- (smallestAngleCorner.y - (yMidOfLongestEdge)))
- {
- dx = dxSecondSuggestion;
- dy = dySecondSuggestion;
- }
- else
- {
- dx = dxFirstSuggestion;
- dy = dyFirstSuggestion;
- }
- }
- else if (neighborNotFound_first)
- {
- //obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y))) >
- (smallestAngleCorner.x - (xMidOfLongestEdge)) *
- (smallestAngleCorner.x - (xMidOfLongestEdge)) +
- (smallestAngleCorner.y - (yMidOfLongestEdge)) *
- (smallestAngleCorner.y - (yMidOfLongestEdge)))
- {
- dx = dxSecondSuggestion;
- dy = dySecondSuggestion;
- }
- else
- {
- dx = dxFirstSuggestion;
- dy = dyFirstSuggestion;
- }
- }
- else if (neighborNotFound_second)
- {
- //obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.x - (xMidOfMiddleEdge)) *
- (smallestAngleCorner.x - (xMidOfMiddleEdge)) +
- (smallestAngleCorner.y - (yMidOfMiddleEdge)) *
- (smallestAngleCorner.y - (yMidOfMiddleEdge))) >
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)))
- {
- dx = dxSecondSuggestion;
- dy = dySecondSuggestion;
- }
- else
- {
- dx = dxFirstSuggestion;
- dy = dyFirstSuggestion;
- }
- }
- else
- {
- //obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dySecondSuggestion + torg.y))) >
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
- (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
- (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)))
- {
- dx = dxSecondSuggestion;
- dy = dySecondSuggestion;
- }
- else
- {
- dx = dxFirstSuggestion;
- dy = dyFirstSuggestion;
- }
- }
- }// end if obtuse
- }// end of relocation
- }// end of almostGood
- Point circumcenter = new Point();
- if (relocated <= 0)
- {
- circumcenter.x = torg.x + dx;
- circumcenter.y = torg.y + dy;
- }
- else
- {
- circumcenter.x = origin_x + dx;
- circumcenter.y = origin_y + dy;
- }
- xi = (yao * dx - xao * dy) * (2.0 * denominator);
- eta = (xdo * dy - ydo * dx) * (2.0 * denominator);
- return circumcenter;
- }
- /// <summary>
- /// Given square of edge lengths of a triangle,
- // determine its orientation
- /// </summary>
- /// <param name="aodist"></param>
- /// <param name="dadist"></param>
- /// <param name="dodist"></param>
- /// <returns>Returns a number indicating an orientation.</returns>
- private int LongestShortestEdge(double aodist, double dadist, double dodist)
- {
- // 123: shortest: aodist // 213: shortest: dadist // 312: shortest: dodist
- // middle: dadist // middle: aodist // middle: aodist
- // longest: dodist // longest: dodist // longest: dadist
- // 132: shortest: aodist // 231: shortest: dadist // 321: shortest: dodist
- // middle: dodist // middle: dodist // middle: dadist
- // longest: dadist // longest: aodist // longest: aodist
- int max = 0, min = 0, mid = 0, minMidMax;
- if (dodist < aodist && dodist < dadist)
- {
- min = 3; // apex is the smallest angle, dodist is the longest edge
- if (aodist < dadist)
- {
- max = 2; // dadist is the longest edge
- mid = 1; // aodist is the middle longest edge
- }
- else
- {
- max = 1; // aodist is the longest edge
- mid = 2; // dadist is the middle longest edge
- }
- }
- else if (aodist < dadist)
- {
- min = 1; // dest is the smallest angle, aodist is the biggest edge
- if (dodist < dadist)
- {
- max = 2; // dadist is the longest edge
- mid = 3; // dodist is the middle longest edge
- }
- else
- {
- max = 3; // dodist is the longest edge
- mid = 2; // dadist is the middle longest edge
- }
- }
- else
- {
- min = 2; // origin is the smallest angle, dadist is the biggest edge
- if (aodist < dodist)
- {
- max = 3; // dodist is the longest edge
- mid = 1; // aodist is the middle longest edge
- }
- else
- {
- max = 1; // aodist is the longest edge
- mid = 3; // dodist is the middle longest edge
- }
- }
- minMidMax = min * 100 + mid * 10 + max;
- // HANDLE ISOSCELES TRIANGLE CASE
- return minMidMax;
- }
- /// <summary>
- /// Checks if smothing is possible for a given bad triangle.
- /// </summary>
- /// <param name="badotri"></param>
- /// <param name="torg"></param>
- /// <param name="tdest"></param>
- /// <param name="tapex"></param>
- /// <param name="newloc">The new location for the point, if somothing is possible.</param>
- /// <returns>Returns 1, 2 or 3 if smoothing will work, 0 otherwise.</returns>
- private int DoSmoothing(Otri badotri, Vertex torg, Vertex tdest, Vertex tapex,
- ref double[] newloc)
- {
- int numpoints_p = 0;// keeps the number of points in a star of point p, q, r
- int numpoints_q = 0;
- int numpoints_r = 0;
- //int i;
- double[] possibilities = new double[6];//there can be more than one possibilities
- int num_pos = 0; // number of possibilities
- int flag1 = 0, flag2 = 0, flag3 = 0;
- bool newLocFound = false;
- //vertex v1, v2, v3; // for ccw test
- //double p1[2], p2[2], p3[2];
- //double temp[2];
- //********************* TRY TO RELOCATE POINT "p" ***************
- // get the surrounding points of p, so this gives us the triangles
- numpoints_p = GetStarPoints(badotri, torg, tdest, tapex, 1, ref points_p);
- // check if the points in counterclockwise order
- // p1[0] = points_p[0]; p1[1] = points_p[1];
- // p2[0] = points_p[2]; p2[1] = points_p[3];
- // p3[0] = points_p[4]; p3[1] = points_p[5];
- // v1 = (vertex)p1; v2 = (vertex)p2; v3 = (vertex)p3;
- // if(counterclockwise(m,b,v1,v2,v3) < 0){
- // // reverse the order to ccw
- // for(i = 0; i < numpoints_p/2; i++){
- // temp[0] = points_p[2*i];
- // temp[1] = points_p[2*i+1];
- // points_p[2*i] = points_p[2*(numpoints_p-1)-2*i];
- // points_p[2*i+1] = points_p[2*(numpoints_p-1)+1-2*i];
- // points_p[2*(numpoints_p-1)-2*i] = temp[0];
- // points_p[2*(numpoints_p-1)+1-2*i] = temp[1];
- // }
- // }
- // m.counterclockcount--;
- // INTERSECTION OF PETALS
- // first check whether the star angles are appropriate for relocation
- if (torg.type == VertexType.FreeVertex && numpoints_p != 0 && ValidPolygonAngles(numpoints_p, points_p))
- {
- //newLocFound = getPetalIntersection(m, b, numpoints_p, points_p, newloc);
- //newLocFound = getPetalIntersectionBruteForce(m, b,numpoints_p, points_p, newloc,torg[0],torg[1]);
- if (behavior.MaxAngle == 0.0)
- {
- newLocFound = GetWedgeIntersectionWithoutMaxAngle(numpoints_p, points_p, ref newloc);
- }
- else
- {
- newLocFound = GetWedgeIntersection(numpoints_p, points_p, ref newloc);
- }
- //printf("call petal intersection for p\n");
- // make sure the relocated point is a free vertex
- if (newLocFound)
- {
- possibilities[0] = newloc[0];// something found
- possibilities[1] = newloc[1];
- num_pos++;// increase the number of possibilities
- flag1 = 1;
- }
- }
- //********************* TRY TO RELOCATE POINT "q" ***************
- // get the surrounding points of q, so this gives us the triangles
- numpoints_q = GetStarPoints(badotri, torg, tdest, tapex, 2, ref points_q);
- // // check if the points in counterclockwise order
- // v1[0] = points_q[0]; v1[1] = points_q[1];
- // v2[0] = points_q[2]; v2[1] = points_q[3];
- // v3[0] = points_q[4]; v3[1] = points_q[5];
- // if(counterclockwise(m,b,v1,v2,v3) < 0){
- // // reverse the order to ccw
- // for(i = 0; i < numpoints_q/2; i++){
- // temp[0] = points_q[2*i];
- // temp[1] = points_q[2*i+1];
- // points_q[2*i] = points_q[2*(numpoints_q-1)-2*i];
- // points_q[2*i+1] = points_q[2*(numpoints_q-1)+1-2*i];
- // points_q[2*(numpoints_q-1)-2*i] = temp[0];
- // points_q[2*(numpoints_q-1)+1-2*i] = temp[1];
- // }
- // }
- // m.counterclockcount--;
- // INTERSECTION OF PETALS
- // first check whether the star angles are appropriate for relocation
- if (tdest.type == VertexType.FreeVertex && numpoints_q != 0 && ValidPolygonAngles(numpoints_q, points_q))
- {
- //newLocFound = getPetalIntersection(m, b,numpoints_q, points_q, newloc);
- //newLocFound = getPetalIntersectionBruteForce(m, b,numpoints_q, points_q, newloc,tapex[0],tapex[1]);
- if (behavior.MaxAngle == 0.0)
- {
- newLocFound = GetWedgeIntersectionWithoutMaxAngle(numpoints_q, points_q, ref newloc);
- }
- else
- {
- newLocFound = GetWedgeIntersection(numpoints_q, points_q, ref newloc);
- }
- //printf("call petal intersection for q\n");
- // make sure the relocated point is a free vertex
- if (newLocFound)
- {
- possibilities[2] = newloc[0];// something found
- possibilities[3] = newloc[1];
- num_pos++;// increase the number of possibilities
- flag2 = 2;
- }
- }
- //********************* TRY TO RELOCATE POINT "q" ***************
- // get the surrounding points of r, so this gives us the triangles
- numpoints_r = GetStarPoints(badotri, torg, tdest, tapex, 3, ref points_r);
- // check if the points in counterclockwise order
- // v1[0] = points_r[0]; v1[1] = points_r[1];
- // v2[0] = points_r[2]; v2[1] = points_r[3];
- // v3[0] = points_r[4]; v3[1] = points_r[5];
- // if(counterclockwise(m,b,v1,v2,v3) < 0){
- // // reverse the order to ccw
- // for(i = 0; i < numpoints_r/2; i++){
- // temp[0] = points_r[2*i];
- // temp[1] = points_r[2*i+1];
- // points_r[2*i] = points_r[2*(numpoints_r-1)-2*i];
- // points_r[2*i+1] = points_r[2*(numpoints_r-1)+1-2*i];
- // points_r[2*(numpoints_r-1)-2*i] = temp[0];
- // points_r[2*(numpoints_r-1)+1-2*i] = temp[1];
- // }
- // }
- // m.counterclockcount--;
- // INTERSECTION OF PETALS
- // first check whether the star angles are appropriate for relocation
- if (tapex.type == VertexType.FreeVertex && numpoints_r != 0 && ValidPolygonAngles(numpoints_r, points_r))
- {
- //newLocFound = getPetalIntersection(m, b,numpoints_r, points_r, newloc);
- //newLocFound = getPetalIntersectionBruteForce(m, b,numpoints_r, points_r, newloc,tdest[0],tdest[1]);
- if (behavior.MaxAngle == 0.0)
- {
- newLocFound = GetWedgeIntersectionWithoutMaxAngle(numpoints_r, points_r, ref newloc);
- }
- else
- {
- newLocFound = GetWedgeIntersection(numpoints_r, points_r, ref newloc);
- }
- //printf("call petal intersection for r\n");
- // make sure the relocated point is a free vertex
- if (newLocFound)
- {
- possibilities[4] = newloc[0];// something found
- possibilities[5] = newloc[1];
- num_pos++;// increase the number of possibilities
- flag3 = 3;
- }
- }
- //printf("numpossibilities %d\n",num_pos);
- //////////// AFTER FINISH CHECKING EVERY POSSIBILITY, CHOOSE ANY OF THE AVAILABLE ONE //////////////////////
- if (num_pos > 0)
- {
- if (flag1 > 0)
- { // suggest to relocate origin
- newloc[0] = possibilities[0];
- newloc[1] = possibilities[1];
- return flag1;
- }
- else
- {
- if (flag2 > 0)
- { // suggest to relocate apex
- newloc[0] = possibilities[2];
- newloc[1] = possibilities[3];
- return flag2;
- }
- else
- {// suggest to relocate destination
- if (flag3 > 0)
- {
- newloc[0] = possibilities[4];
- newloc[1] = possibilities[5];
- return flag3;
- }
- }
- }
- }
- return 0;// could not find any good relocation
- }
- /// <summary>
- /// Finds the star of a given point.
- /// </summary>
- /// <param name="badotri"></param>
- /// <param name="p"></param>
- /// <param name="q"></param>
- /// <param name="r"></param>
- /// <param name="whichPoint"></param>
- /// <param name="points">List of points on the star of the given point.</param>
- /// <returns>Number of points on the star of the given point.</returns>
- private int GetStarPoints(Otri badotri, Vertex p, Vertex q, Vertex r,
- int whichPoint, ref double[] points)
- {
- Otri neighotri = default(Otri); // for return value of the function
- Otri tempotri; // for temporary usage
- double first_x = 0, first_y = 0; // keeps the first point to be considered
- double second_x = 0, second_y = 0; // for determining the edge we will begin
- double third_x = 0, third_y = 0; // termination
- double[] returnPoint = new double[2]; // for keeping the returned point
- int numvertices = 0; // for keeping number of surrounding vertices
- // first determine which point to be used to find its neighbor triangles
- switch (whichPoint)
- {
- case 1:
- first_x = p.x; // point at the center
- first_y = p.y;
- second_x = r.x; // second vertex of first edge to consider
- second_y = r.y;
- third_x = q.x; // for terminating the search
- third_y = q.y;
- break;
- case 2:
- first_x = q.x; // point at the center
- first_y = q.y;
- second_x = p.x; // second vertex of first edge to consider
- second_y = p.y;
- third_x = r.x; // for terminating the search
- third_y = r.y;
- break;
- case 3:
- first_x = r.x; // point at the center
- first_y = r.y;
- second_x = q.x; // second vertex of first edge to consider
- second_y = q.y;
- third_x = p.x; // for terminating the search
- third_y = p.y;
- break;
- }
- tempotri = badotri;
- // add first point as the end of first edge
- points[numvertices] = second_x;
- numvertices++;
- points[numvertices] = second_y;
- numvertices++;
- // assign as dummy value
- returnPoint[0] = second_x; returnPoint[1] = second_y;
- // until we reach the third point of the beginning triangle
- do
- {
- // find the neighbor's third point where it is incident to given edge
- if (!GetNeighborsVertex(tempotri, first_x, first_y, second_x, second_y, ref returnPoint, ref neighotri))
- {
- // go to next triangle
- tempotri = neighotri;
- // now the second point is the neighbor's third vertex
- second_x = returnPoint[0];
- second_y = returnPoint[1];
- // add a new point to the list of surrounding points
- points[numvertices] = returnPoint[0];
- numvertices++;
- points[numvertices] = returnPoint[1];
- numvertices++;
- }
- else
- {
- numvertices = 0;
- break;
- }
- }
- while (!((Math.Abs(returnPoint[0] - third_x) <= EPS) &&
- (Math.Abs(returnPoint[1] - third_y) <= EPS)));
- return numvertices / 2;
- }
- /// <summary>
- /// Gets a neighbours vertex.
- /// </summary>
- /// <param name="badotri"></param>
- /// <param name="first_x"></param>
- /// <param name="first_y"></param>
- /// <param name="second_x"></param>
- /// <param name="second_y"></param>
- /// <param name="thirdpoint">Neighbor's third vertex incident to given edge.</param>
- /// <param name="neighotri">Pointer for the neighbor triangle.</param>
- /// <returns>Returns true if vertex was found.</returns>
- private bool GetNeighborsVertex(Otri badotri,
- double first_x, double first_y,
- double second_x, double second_y,
- ref double[] thirdpoint, ref Otri neighotri)
- {
- Otri neighbor = default(Otri); // keeps the neighbor triangles
- bool notFound = false; // boolean variable if we can find that neighbor or not
- // for keeping the vertices of the neighbor triangle
- Vertex neighborvertex_1 = null;
- Vertex neighborvertex_2 = null;
- Vertex neighborvertex_3 = null;
- // used for finding neighbor triangle
- int firstVertexMatched = 0, secondVertexMatched = 0; // to find the correct neighbor
- //triangle ptr; // Temporary variable used by sym()
- //int i; // index variable
- // find neighbors
- // Check each of the triangle's three neighbors to find the correct one
- for (badotri.orient = 0; badotri.orient < 3; badotri.orient++)
- {
- // Find the neighbor.
- badotri.Sym(ref neighbor);
- // check if it is the one we are looking for by checking the corners
- // first check if the neighbor is nonexistent, since it can be on the border
- if (neighbor.tri.id != Mesh.DUMMY)
- {
- // then check if two wanted corners are also in this triangle
- // take the vertices of the candidate neighbor
- neighborvertex_1 = neighbor.Org();
- neighborvertex_2 = neighbor.Dest();
- neighborvertex_3 = neighbor.Apex();
- // check if it is really a triangle
- if ((neighborvertex_1.x == neighborvertex_2.x && neighborvertex_1.y == neighborvertex_2.y)
- || (neighborvertex_2.x == neighborvertex_3.x && neighborvertex_2.y == neighborvertex_3.y)
- || (neighborvertex_1.x == neighborvertex_3.x && neighborvertex_1.y == neighborvertex_3.y))
- {
- //printf("Two vertices are the same!!!!!!!\n");
- }
- else
- {
- // begin searching for the correct neighbor triangle
- firstVertexMatched = 0;
- if ((Math.Abs(first_x - neighborvertex_1.x) < EPS) &&
- (Math.Abs(first_y - neighborvertex_1.y) < EPS))
- {
- firstVertexMatched = 11; // neighbor's 1st vertex is matched to first vertex
- }
- else if ((Math.Abs(first_x - neighborvertex_2.x) < EPS) &&
- (Math.Abs(first_y - neighborvertex_2.y) < EPS))
- {
- firstVertexMatched = 12; // neighbor's 2nd vertex is matched to first vertex
- }
- else if ((Math.Abs(first_x - neighborvertex_3.x) < EPS) &&
- (Math.Abs(first_y - neighborvertex_3.y) < EPS))
- {
- firstVertexMatched = 13; // neighbor's 3rd vertex is matched to first vertex
- }/*else{
- // none of them matched
- } // end of first vertex matching */
- secondVertexMatched = 0;
- if ((Math.Abs(second_x - neighborvertex_1.x) < EPS) &&
- (Math.Abs(second_y - neighborvertex_1.y) < EPS))
- {
- secondVertexMatched = 21; // neighbor's 1st vertex is matched to second vertex
- }
- else if ((Math.Abs(second_x - neighborvertex_2.x) < EPS) &&
- (Math.Abs(second_y - neighborvertex_2.y) < EPS))
- {
- secondVertexMatched = 22; // neighbor's 2nd vertex is matched to second vertex
- }
- else if ((Math.Abs(second_x - neighborvertex_3.x) < EPS) &&
- (Math.Abs(second_y - neighborvertex_3.y) < EPS))
- {
- secondVertexMatched = 23; // neighbor's 3rd vertex is matched to second vertex
- }/*else{
- // none of them matched
- } // end of second vertex matching*/
- }
- }// if neighbor exists or not
- if (((firstVertexMatched == 11) && (secondVertexMatched == 22 || secondVertexMatched == 23))
- || ((firstVertexMatched == 12) && (secondVertexMatched == 21 || secondVertexMatched == 23))
- || ((firstVertexMatched == 13) && (secondVertexMatched == 21 || secondVertexMatched == 22)))
- break;
- }// end of for loop over all orientations
- switch (firstVertexMatched)
- {
- case 0:
- notFound = true;
- break;
- case 11:
- if (secondVertexMatched == 22)
- {
- thirdpoint[0] = neighborvertex_3.x;
- thirdpoint[1] = neighborvertex_3.y;
- }
- else if (secondVertexMatched == 23)
- {
- thirdpoint[0] = neighborvertex_2.x;
- thirdpoint[1] = neighborvertex_2.y;
- }
- else { notFound = true; }
- break;
- case 12:
- if (secondVertexMatched == 21)
- {
- thirdpoint[0] = neighborvertex_3.x;
- thirdpoint[1] = neighborvertex_3.y;
- }
- else if (secondVertexMatched == 23)
- {
- thirdpoint[0] = neighborvertex_1.x;
- thirdpoint[1] = neighborvertex_1.y;
- }
- else { notFound = true; }
- break;
- case 13:
- if (secondVertexMatched == 21)
- {
- thirdpoint[0] = neighborvertex_2.x;
- thirdpoint[1] = neighborvertex_2.y;
- }
- else if (secondVertexMatched == 22)
- {
- thirdpoint[0] = neighborvertex_1.x;
- thirdpoint[1] = neighborvertex_1.y;
- }
- else { notFound = true; }
- break;
- default:
- if (secondVertexMatched == 0) { notFound = true; }
- break;
- }
- // pointer of the neighbor triangle
- neighotri = neighbor;
- return notFound;
- }
- /// <summary>
- /// Find a new point location by wedge intersection.
- /// </summary>
- /// <param name="numpoints"></param>
- /// <param name="points"></param>
- /// <param name="newloc">A new location for the point according to surrounding points.</param>
- /// <returns>Returns true if new location found</returns>
- private bool GetWedgeIntersectionWithoutMaxAngle(int numpoints,
- double[] points, ref double[] newloc)
- {
- //double total_x = 0;
- //double total_y = 0;
- double x0, y0, x1, y1, x2, y2;
- //double compConst = 0.01; // for comparing real numbers
- double x01, y01;
- //double x12, y12;
- //double ax, ay, bx, by; //two intersections of two petals disks
- double d01;//, d12
- //double petalx0, petaly0, petalr0, petalx1, petaly1, petalr1;
- //double p[5];
- // Resize work arrays
- if (2 * numpoints > petalx.Length)
- {
- petalx = new double[2 * numpoints];
- petaly = new double[2 * numpoints];
- petalr = new double[2 * numpoints];
- wedges = new double[2 * numpoints * 16 + 36];
- }
- double xmid, ymid, dist, x3, y3;
- double x_1, y_1, x_2, y_2, x_3, y_3, x_4, y_4, tempx, tempy;
- double ux, uy;
- double alpha;
- double[] p1 = new double[3];
- //double poly_points;
- int numpolypoints = 0;
- //int numBadTriangle;
- int i, j;
- int s, flag, count, num;
- double petalcenterconstant, petalradiusconstant;
- x0 = points[2 * numpoints - 4];
- y0 = points[2 * numpoints - 3];
- x1 = points[2 * numpoints - 2];
- y1 = points[2 * numpoints - 1];
- // minimum angle
- alpha = behavior.MinAngle * Math.PI / 180.0;
- // initialize the constants
- if (behavior.goodAngle == 1.0)
- {
- petalcenterconstant = 0;
- petalradiusconstant = 0;
- }
- else
- {
- petalcenterconstant = 0.5 / Math.Tan(alpha);
- petalradiusconstant = 0.5 / Math.Sin(alpha);
- }
- for (i = 0; i < numpoints * 2; i = i + 2)
- {
- x2 = points[i];
- y2 = points[i + 1];
- //printf("POLYGON POINTS (p,q) #%d (%.12f, %.12f) (%.12f, %.12f)\n", i/2, x0, y0,x1, y1);
- x01 = x1 - x0;
- y01 = y1 - y0;
- d01 = Math.Sqrt(x01 * x01 + y01 * y01);
- // find the petal of each edge 01;
- // printf("PETAL CONSTANT (%.12f, %.12f)\n",
- // b.petalcenterconstant, b.petalradiusconstant );
- // printf("PETAL DIFFS (%.6f, %.6f, %.4f)\n", x01, y01, d01);
- petalx[i / 2] = x0 + 0.5 * x01 - petalcenterconstant * y01;
- petaly[i / 2] = y0 + 0.5 * y01 + petalcenterconstant * x01;
- petalr[i / 2] = petalradiusconstant * d01;
- petalx[numpoints + i / 2] = petalx[i / 2];
- petaly[numpoints + i / 2] = petaly[i / 2];
- petalr[numpoints + i / 2] = petalr[i / 2];
- //printf("PETAL POINTS #%d (%.12f, %.12f) R= %.12f\n", i/2, petalx[i/2],petaly[i/2], petalr[i/2]);
- /// FIRST FIND THE HALF-PLANE POINTS FOR EACH PETAL
- xmid = (x0 + x1) / 2.0; // mid point of pq
- ymid = (y0 + y1) / 2.0;
- // distance between xmid and petal center
- dist = Math.Sqrt((petalx[i / 2] - xmid) * (petalx[i / 2] - xmid) + (petaly[i / 2] - ymid) * (petaly[i / 2] - ymid));
- // find the unit vector goes from mid point to petal center
- ux = (petalx[i / 2] - xmid) / dist;
- uy = (petaly[i / 2] - ymid) / dist;
- // find the third point other than p and q
- x3 = petalx[i / 2] + ux * petalr[i / 2];
- y3 = petaly[i / 2] + uy * petalr[i / 2];
- /// FIND THE LINE POINTS BY THE ROTATION MATRIX
- // cw rotation matrix [cosX sinX; -sinX cosX]
- // cw rotation about (x,y) [ux*cosX + uy*sinX + x - x*cosX - y*sinX; -ux*sinX + uy*cosX + y + x*sinX - y*cosX]
- // ccw rotation matrix [cosX -sinX; sinX cosX]
- // ccw rotation about (x,y) [ux*cosX - uy*sinX + x - x*cosX + y*sinX; ux*sinX + uy*cosX + y - x*sinX - y*cosX]
- /// LINE #1: (x1,y1) & (x_1,y_1)
- // vector from p to q
- ux = x1 - x0;
- uy = y1 - y0;
- // rotate the vector around p = (x0,y0) in ccw by alpha degrees
- x_1 = x1 * Math.Cos(alpha) - y1 * Math.Sin(alpha) + x0 - x0 * Math.Cos(alpha) + y0 * Math.Sin(alpha);
- y_1 = x1 * Math.Sin(alpha) + y1 * Math.Cos(alpha) + y0 - x0 * Math.Sin(alpha) - y0 * Math.Cos(alpha);
- // add these to wedges list as lines in order
- wedges[i * 16] = x0; wedges[i * 16 + 1] = y0;
- wedges[i * 16 + 2] = x_1; wedges[i * 16 + 3] = y_1;
- //printf("LINE #1 (%.12f, %.12f) (%.12f, %.12f)\n", x0,y0,x_1,y_1);
- /// LINE #2: (x2,y2) & (x_2,y_2)
- // vector from p to q
- ux = x0 - x1;
- uy = y0 - y1;
- // rotate the vector around q = (x1,y1) in cw by alpha degrees
- x_2 = x0 * Math.Cos(alpha) + y0 * Math.Sin(alpha) + x1 - x1 * Math.Cos(alpha) - y1 * Math.Sin(alpha);
- y_2 = -x0 * Math.Sin(alpha) + y0 * Math.Cos(alpha) + y1 + x1 * Math.Sin(alpha) - y1 * Math.Cos(alpha);
- // add these to wedges list as lines in order
- wedges[i * 16 + 4] = x_2; wedges[i * 16 + 5] = y_2;
- wedges[i * 16 + 6] = x1; wedges[i * 16 + 7] = y1;
- //printf("LINE #2 (%.12f, %.12f) (%.12f, %.12f)\n", x_2,y_2,x1,y1);
- // vector from (petalx, petaly) to (x3,y3)
- ux = x3 - petalx[i / 2];
- uy = y3 - petaly[i / 2];
- tempx = x3; tempy = y3;
- /// LINE #3, #4, #5: (x3,y3) & (x_3,y_3)
- for (j = 1; j < 4; j++)
- {
- // rotate the vector around (petalx,petaly) in cw by (60 - alpha)*j degrees
- x_3 = x3 * Math.Cos((Math.PI / 3.0 - alpha) * j) + y3 * Math.Sin((Math.PI / 3.0 - alpha) * j) + petalx[i / 2] - petalx[i / 2] * Math.Cos((Math.PI / 3.0 - alpha) * j) - petaly[i / 2] * Math.Sin((Math.PI / 3.0 - alpha) * j);
- y_3 = -x3 * Math.Sin((Math.PI / 3.0 - alpha) * j) + y3 * Math.Cos((Math.PI / 3.0 - alpha) * j) + petaly[i / 2] + petalx[i / 2] * Math.Sin((Math.PI / 3.0 - alpha) * j) - petaly[i / 2] * Math.Cos((Math.PI / 3.0 - alpha) * j);
- // add these to wedges list as lines in order
- wedges[i * 16 + 8 + 4 * (j - 1)] = x_3; wedges[i * 16 + 9 + 4 * (j - 1)] = y_3;
- wedges[i * 16 + 10 + 4 * (j - 1)] = tempx; wedges[i * 16 + 11 + 4 * (j - 1)] = tempy;
- tempx = x_3; tempy = y_3;
- }
- tempx = x3; tempy = y3;
- /// LINE #6, #7, #8: (x3,y3) & (x_4,y_4)
- for (j = 1; j < 4; j++)
- {
- // rotate the vector around (petalx,petaly) in ccw by (60 - alpha)*j degrees
- x_4 = x3 * Math.Cos((Math.PI / 3.0 - alpha) * j) - y3 * Math.Sin((Math.PI / 3.0 - alpha) * j) + petalx[i / 2] - petalx[i / 2] * Math.Cos((Math.PI / 3.0 - alpha) * j) + petaly[i / 2] * Math.Sin((Math.PI / 3.0 - alpha) * j);
- y_4 = x3 * Math.Sin((Math.PI / 3.0 - alpha) * j) + y3 * Math.Cos((Math.PI / 3.0 - alpha) * j) + petaly[i / 2] - petalx[i / 2] * Math.Sin((Math.PI / 3.0 - alpha) * j) - petaly[i / 2] * Math.Cos((Math.PI / 3.0 - alpha) * j);
- // add these to wedges list as lines in order
- wedges[i * 16 + 20 + 4 * (j - 1)] = tempx; wedges[i * 16 + 21 + 4 * (j - 1)] = tempy;
- wedges[i * 16 + 22 + 4 * (j - 1)] = x_4; wedges[i * 16 + 23 + 4 * (j - 1)] = y_4;
- tempx = x_4; tempy = y_4;
- }
- //printf("LINE #3 (%.12f, %.12f) (%.12f, %.12f)\n", x_3,y_3,x3,y3);
- //printf("LINE #4 (%.12f, %.12f) (%.12f, %.12f)\n", x3,y3,x_4,y_4);
- /// IF IT IS THE FIRST ONE, FIND THE CONVEX POLYGON
- if (i == 0)
- {
- // line1 & line2: p1
- LineLineIntersection(x0, y0, x_1, y_1, x1, y1, x_2, y_2, ref p1);
- if ((p1[0] == 1.0))
- {
- // #0
- initialConvexPoly[0] = p1[1]; initialConvexPoly[1] = p1[2];
- // #1
- initialConvexPoly[2] = wedges[i * 16 + 16]; initialConvexPoly[3] = wedges[i * 16 + 17];
- // #2
- initialConvexPoly[4] = wedges[i * 16 + 12]; initialConvexPoly[5] = wedges[i * 16 + 13];
- // #3
- initialConvexPoly[6] = wedges[i * 16 + 8]; initialConvexPoly[7] = wedges[i * 16 + 9];
- // #4
- initialConvexPoly[8] = x3; initialConvexPoly[9] = y3;
- // #5
- initialConvexPoly[10] = wedges[i * 16 + 22]; initialConvexPoly[11] = wedges[i * 16 + 23];
- // #6
- initialConvexPoly[12] = wedges[i * 16 + 26]; initialConvexPoly[13] = wedges[i * 16 + 27];
- // #7
- initialConvexPoly[14] = wedges[i * 16 + 30]; initialConvexPoly[15] = wedges[i * 16 + 31];
- //printf("INITIAL POLY [%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f]\n", initialConvexPoly[0],initialConvexPoly[1],initialConvexPoly[2],initialConvexPoly[3],initialConvexPoly[4],initialConvexPoly[5],initialConvexPoly[6],initialConvexPoly[7],initialConvexPoly[8],initialConvexPoly[9],initialConvexPoly[10],initialConvexPoly[11],initialConvexPoly[12],initialConvexPoly[13],initialConvexPoly[14],initialConvexPoly[15]);
- }
- }
- x0 = x1; y0 = y1;
- x1 = x2; y1 = y2;
- }
- /// HALF PLANE INTERSECTION: START SPLITTING THE INITIAL POLYGON TO FIND FEASIBLE REGION
- if (numpoints != 0)
- {
- // first intersect the opposite located ones
- s = (numpoints - 1) / 2 + 1;
- flag = 0;
- count = 0;
- i = 1;
- num = 8;
- for (j = 0; j < 32; j = j + 4)
- {
- numpolypoints = HalfPlaneIntersection(num, ref initialConvexPoly, wedges[32 * s + j], wedges[32 * s + 1 + j], wedges[32 * s + 2 + j], wedges[32 * s + 3 + j]);
- if (numpolypoints == 0)
- return false;
- else
- num = numpolypoints;
- }
- count++;
- while (count < numpoints - 1)
- {
- for (j = 0; j < 32; j = j + 4)
- {
- numpolypoints = HalfPlaneIntersection(num, ref initialConvexPoly, wedges[32 * (i + s * flag) + j], wedges[32 * (i + s * flag) + 1 + j], wedges[32 * (i + s * flag) + 2 + j], wedges[32 * (i + s * flag) + 3 + j]);
- if (numpolypoints == 0)
- return false;
- else
- num = numpolypoints;
- }
- i = i + flag;
- flag = (flag + 1) % 2;
- count++;
- }
- /// IF THERE IS A FEASIBLE INTERSECTION POLYGON, FIND ITS CENTROID AS THE NEW LOCATION
- FindPolyCentroid(numpolypoints, initialConvexPoly, ref newloc);
- if (behavior.fixedArea)
- {
- // numBadTriangle = 0;
- // for(j= 0; j < numpoints *2-2; j = j+2){
- // if(testTriangleAngleArea(m,b,&newloc[0],&newloc[1], &points[j], &points[j+1], &points[j+2], &points[j+3] )){
- // numBadTriangle++;
- // }
- // }
- // if(testTriangleAngleArea(m,b, &newloc[0],&newloc[1], &points[0], &points[1], &points[numpoints*2-2], &points[numpoints*2-1] )){
- // numBadTriangle++;
- // }
- //
- // if (numBadTriangle == 0) {
- //
- // return 1;
- // }
- }
- else
- {
- //printf("yes, we found a feasible region num: %d newloc (%.12f,%.12f)\n", numpolypoints, newloc[0], newloc[1]);
- // for(i = 0; i < 2*numpolypoints; i = i+2){
- // printf("point %d) (%.12f,%.12f)\n", i/2, initialConvexPoly[i], initialConvexPoly[i+1]);
- // }
- // printf("numpoints %d\n",numpoints);
- return true;
- }
- }
- return false;
- }
- /// <summary>
- /// Find a new point location by wedge intersection.
- /// </summary>
- /// <param name="numpoints"></param>
- /// <param name="points"></param>
- /// <param name="newloc">A new location for the point according to surrounding points.</param>
- /// <returns>Returns true if new location found</returns>
- private bool GetWedgeIntersection(int numpoints, double[] points, ref double[] newloc)
- {
- //double total_x = 0;
- //double total_y = 0;
- double x0, y0, x1, y1, x2, y2;
- //double compConst = 0.01; // for comparing real numbers
- double x01, y01;
- //double x12, y12;
- //double ax, ay, bx, by; //two intersections of two petals disks
- double d01;//, d12
- //double petalx0, petaly1, petaly0, petalr0, petalx1, petalr1;
- //double p[5];
- // Resize work arrays
- if (2 * numpoints > petalx.Length)
- {
- petalx = new double[2 * numpoints];
- petaly = new double[2 * numpoints];
- petalr = new double[2 * numpoints];
- wedges = new double[2 * numpoints * 20 + 40];
- }
- double xmid, ymid, dist, x3, y3;
- double x_1, y_1, x_2, y_2, x_3, y_3, x_4, y_4, tempx, tempy, x_5, y_5, x_6, y_6;
- double ux, uy;
- double[] p1 = new double[3];
- double[] p2 = new double[3];
- double[] p3 = new double[3];
- double[] p4 = new double[3];
- //double poly_points;
- int numpolypoints = 0;
- int howManyPoints = 0; // keeps the number of points used for representing the wedge
- double line345 = 4.0, line789 = 4.0; // flag keeping which line to skip or construct
- int numBadTriangle;
- int i, j, k;
- int s, flag, count, num;
- int n, e;
- double weight;
- double petalcenterconstant, petalradiusconstant;
- x0 = points[2 * numpoints - 4];
- y0 = points[2 * numpoints - 3];
- x1 = points[2 * numpoints - 2];
- y1 = points[2 * numpoints - 1];
- // minimum / maximum angle
- double alpha, sinAlpha, cosAlpha, beta, sinBeta, cosBeta;
- alpha = behavior.MinAngle * Math.PI / 180.0;
- sinAlpha = Math.Sin(alpha);
- cosAlpha = Math.Cos(alpha);
- beta = behavior.MaxAngle * Math.PI / 180.0;
- sinBeta = Math.Sin(beta);
- cosBeta = Math.Cos(beta);
- // initialize the constants
- if (behavior.goodAngle == 1.0)
- {
- petalcenterconstant = 0;
- petalradiusconstant = 0;
- }
- else
- {
- petalcenterconstant = 0.5 / Math.Tan(alpha);
- petalradiusconstant = 0.5 / Math.Sin(alpha);
- }
- for (i = 0; i < numpoints * 2; i = i + 2)
- {
- // go to the next point
- x2 = points[i];
- y2 = points[i + 1];
- // printf("POLYGON POINTS (p,q) #%d (%.12f, %.12f) (%.12f, %.12f)\n", i/2, x0, y0,x1, y1);
- x01 = x1 - x0;
- y01 = y1 - y0;
- d01 = Math.Sqrt(x01 * x01 + y01 * y01);
- // find the petal of each edge 01;
- // printf("PETAL CONSTANT (%.12f, %.12f)\n",
- // b.petalcenterconstant, b.petalradiusconstant );
- // printf("PETAL DIFFS (%.6f, %.6f, %.4f)\n", x01, y01, d01);
- //printf("i:%d numpoints:%d\n", i, numpoints);
- petalx[i / 2] = x0 + 0.5 * x01 - petalcenterconstant * y01;
- petaly[i / 2] = y0 + 0.5 * y01 + petalcenterconstant * x01;
- petalr[i / 2] = petalradiusconstant * d01;
- petalx[numpoints + i / 2] = petalx[i / 2];
- petaly[numpoints + i / 2] = petaly[i / 2];
- petalr[numpoints + i / 2] = petalr[i / 2];
- //printf("PETAL POINTS #%d (%.12f, %.12f) R= %.12f\n", i/2, petalx[i/2],petaly[i/2], petalr[i/2]);
- /// FIRST FIND THE HALF-PLANE POINTS FOR EACH PETAL
- xmid = (x0 + x1) / 2.0; // mid point of pq
- ymid = (y0 + y1) / 2.0;
- // distance between xmid and petal center
- dist = Math.Sqrt((petalx[i / 2] - xmid) * (petalx[i / 2] - xmid) + (petaly[i / 2] - ymid) * (petaly[i / 2] - ymid));
- // find the unit vector goes from mid point to petal center
- ux = (petalx[i / 2] - xmid) / dist;
- uy = (petaly[i / 2] - ymid) / dist;
- // find the third point other than p and q
- x3 = petalx[i / 2] + ux * petalr[i / 2];
- y3 = petaly[i / 2] + uy * petalr[i / 2];
- /// FIND THE LINE POINTS BY THE ROTATION MATRIX
- // cw rotation matrix [cosX sinX; -sinX cosX]
- // cw rotation about (x,y) [ux*cosX + uy*sinX + x - x*cosX - y*sinX; -ux*sinX + uy*cosX + y + x*sinX - y*cosX]
- // ccw rotation matrix [cosX -sinX; sinX cosX]
- // ccw rotation about (x,y) [ux*cosX - uy*sinX + x - x*cosX + y*sinX; ux*sinX + uy*cosX + y - x*sinX - y*cosX]
- /// LINE #1: (x1,y1) & (x_1,y_1)
- // vector from p to q
- ux = x1 - x0;
- uy = y1 - y0;
- // rotate the vector around p = (x0,y0) in ccw by alpha degrees
- x_1 = x1 * cosAlpha - y1 * sinAlpha + x0 - x0 * cosAlpha + y0 * sinAlpha;
- y_1 = x1 * sinAlpha + y1 * cosAlpha + y0 - x0 * sinAlpha - y0 * cosAlpha;
- // add these to wedges list as lines in order
- wedges[i * 20] = x0; wedges[i * 20 + 1] = y0;
- wedges[i * 20 + 2] = x_1; wedges[i * 20 + 3] = y_1;
- //printf("LINE #1 (%.12f, %.12f) (%.12f, %.12f)\n", x0,y0,x_1,y_1);
- /// LINE #2: (x2,y2) & (x_2,y_2)
- // vector from q to p
- ux = x0 - x1;
- uy = y0 - y1;
- // rotate the vector around q = (x1,y1) in cw by alpha degrees
- x_2 = x0 * cosAlpha + y0 * sinAlpha + x1 - x1 * cosAlpha - y1 * sinAlpha;
- y_2 = -x0 * sinAlpha + y0 * cosAlpha + y1 + x1 * sinAlpha - y1 * cosAlpha;
- // add these to wedges list as lines in order
- wedges[i * 20 + 4] = x_2; wedges[i * 20 + 5] = y_2;
- wedges[i * 20 + 6] = x1; wedges[i * 20 + 7] = y1;
- //printf("LINE #2 (%.12f, %.12f) (%.12f, %.12f)\n", x_2,y_2,x1,y1);
- // vector from (petalx, petaly) to (x3,y3)
- ux = x3 - petalx[i / 2];
- uy = y3 - petaly[i / 2];
- tempx = x3; tempy = y3;
- /// DETERMINE HOW MANY POINTS TO USE ACCORDING TO THE MINANGLE-MAXANGLE COMBINATION
- // petal center angle
- alpha = (2.0 * behavior.MaxAngle + behavior.MinAngle - 180.0);
- if (alpha <= 0.0)
- {// when only angle lines needed
- // 4 point case
- howManyPoints = 4;
- //printf("4 point case\n");
- line345 = 1.0;
- line789 = 1.0;
- }
- else if (alpha <= 5.0)
- {// when only angle lines plus two other lines are needed
- // 6 point case
- howManyPoints = 6;
- //printf("6 point case\n");
- line345 = 2.0;
- line789 = 2.0;
- }
- else if (alpha <= 10.0)
- {// when we need more lines
- // 8 point case
- howManyPoints = 8;
- line345 = 3.0;
- line789 = 3.0;
- //printf("8 point case\n");
- }
- else
- {// when we have a big wedge
- // 10 point case
- howManyPoints = 10;
- //printf("10 point case\n");
- line345 = 4.0;
- line789 = 4.0;
- }
- alpha = alpha * Math.PI / 180.0;
- /// LINE #3, #4, #5: (x3,y3) & (x_3,y_3)
- for (j = 1; j < line345; j++)
- {
- if (line345 == 1)
- continue;
- // rotate the vector around (petalx,petaly) in cw by (alpha/3.0)*j degrees
- x_3 = x3 * Math.Cos((alpha / (line345 - 1.0)) * j) + y3 * Math.Sin(((alpha / (line345 - 1.0)) * j)) + petalx[i / 2] - petalx[i / 2] * Math.Cos(((alpha / (line345 - 1.0)) * j)) - petaly[i / 2] * Math.Sin(((alpha / (line345 - 1.0)) * j));
- y_3 = -x3 * Math.Sin(((alpha / (line345 - 1.0)) * j)) + y3 * Math.Cos(((alpha / (line345 - 1.0)) * j)) + petaly[i / 2] + petalx[i / 2] * Math.Sin(((alpha / (line345 - 1.0)) * j)) - petaly[i / 2] * Math.Cos(((alpha / (line345 - 1.0)) * j));
- // add these to wedges list as lines in order
- wedges[i * 20 + 8 + 4 * (j - 1)] = x_3; wedges[i * 20 + 9 + 4 * (j - 1)] = y_3;
- wedges[i * 20 + 10 + 4 * (j - 1)] = tempx; wedges[i * 20 + 11 + 4 * (j - 1)] = tempy;
- tempx = x_3; tempy = y_3;
- }
- /// LINE #6: (x2,y2) & (x_3,y_3)
- // vector from q to p
- ux = x0 - x1;
- uy = y0 - y1;
- // rotate the vector around q = (x1,y1) in cw by alpha degrees
- x_5 = x0 * cosBeta + y0 * sinBeta + x1 - x1 * cosBeta - y1 * sinBeta;
- y_5 = -x0 * sinBeta + y0 * cosBeta + y1 + x1 * sinBeta - y1 * cosBeta;
- wedges[i * 20 + 20] = x1; wedges[i * 20 + 21] = y1;
- wedges[i * 20 + 22] = x_5; wedges[i * 20 + 23] = y_5;
- tempx = x3; tempy = y3;
- /// LINE #7, #8, #9: (x3,y3) & (x_4,y_4)
- for (j = 1; j < line789; j++)
- {
- if (line789 == 1)
- continue;
- // rotate the vector around (petalx,petaly) in ccw by (alpha/3.0)*j degrees
- x_4 = x3 * Math.Cos((alpha / (line789 - 1.0)) * j) - y3 * Math.Sin((alpha / (line789 - 1.0)) * j) + petalx[i / 2] - petalx[i / 2] * Math.Cos((alpha / (line789 - 1.0)) * j) + petaly[i / 2] * Math.Sin((alpha / (line789 - 1.0)) * j);
- y_4 = x3 * Math.Sin((alpha / (line789 - 1.0)) * j) + y3 * Math.Cos((alpha / (line789 - 1.0)) * j) + petaly[i / 2] - petalx[i / 2] * Math.Sin((alpha / (line789 - 1.0)) * j) - petaly[i / 2] * Math.Cos((alpha / (line789 - 1.0)) * j);
- // add these to wedges list as lines in order
- wedges[i * 20 + 24 + 4 * (j - 1)] = tempx; wedges[i * 20 + 25 + 4 * (j - 1)] = tempy;
- wedges[i * 20 + 26 + 4 * (j - 1)] = x_4; wedges[i * 20 + 27 + 4 * (j - 1)] = y_4;
- tempx = x_4; tempy = y_4;
- }
- /// LINE #10: (x1,y1) & (x_3,y_3)
- // vector from p to q
- ux = x1 - x0;
- uy = y1 - y0;
- // rotate the vector around p = (x0,y0) in ccw by alpha degrees
- x_6 = x1 * cosBeta - y1 * sinBeta + x0 - x0 * cosBeta + y0 * sinBeta;
- y_6 = x1 * sinBeta + y1 * cosBeta + y0 - x0 * sinBeta - y0 * cosBeta;
- wedges[i * 20 + 36] = x_6; wedges[i * 20 + 37] = y_6;
- wedges[i * 20 + 38] = x0; wedges[i * 20 + 39] = y0;
- //printf("LINE #1 (%.12f, %.12f) (%.12f, %.12f)\n", x0,y0,x_1,y_1);
- /// IF IT IS THE FIRST ONE, FIND THE CONVEX POLYGON
- if (i == 0)
- {
- switch (howManyPoints)
- {
- case 4:
- // line1 & line2 & line3 & line4
- LineLineIntersection(x0, y0, x_1, y_1, x1, y1, x_2, y_2, ref p1);
- LineLineIntersection(x0, y0, x_1, y_1, x1, y1, x_5, y_5, ref p2);
- LineLineIntersection(x0, y0, x_6, y_6, x1, y1, x_5, y_5, ref p3);
- LineLineIntersection(x0, y0, x_6, y_6, x1, y1, x_2, y_2, ref p4);
- if ((p1[0] == 1.0) && (p2[0] == 1.0) && (p3[0] == 1.0) && (p4[0] == 1.0))
- {
- // #0
- initialConvexPoly[0] = p1[1]; initialConvexPoly[1] = p1[2];
- // #1
- initialConvexPoly[2] = p2[1]; initialConvexPoly[3] = p2[2];
- // #2
- initialConvexPoly[4] = p3[1]; initialConvexPoly[5] = p3[2];
- // #3
- initialConvexPoly[6] = p4[1]; initialConvexPoly[7] = p4[2];
- }
- break;
- case 6:
- // line1 & line2 & line3
- LineLineIntersection(x0, y0, x_1, y_1, x1, y1, x_2, y_2, ref p1);
- LineLineIntersection(x0, y0, x_1, y_1, x1, y1, x_5, y_5, ref p2);
- LineLineIntersection(x0, y0, x_6, y_6, x1, y1, x_2, y_2, ref p3);
- if ((p1[0] == 1.0) && (p2[0] == 1.0) && (p3[0] == 1.0))
- {
- // #0
- initialConvexPoly[0] = p1[1]; initialConvexPoly[1] = p1[2];
- // #1
- initialConvexPoly[2] = p2[1]; initialConvexPoly[3] = p2[2];
- // #2
- initialConvexPoly[4] = wedges[i * 20 + 8]; initialConvexPoly[5] = wedges[i * 20 + 9];
- // #3
- initialConvexPoly[6] = x3; initialConvexPoly[7] = y3;
- // #4
- initialConvexPoly[8] = wedges[i * 20 + 26]; initialConvexPoly[9] = wedges[i * 20 + 27];
- // #5
- initialConvexPoly[10] = p3[1]; initialConvexPoly[11] = p3[2];
- }
- break;
- case 8:
- // line1 & line2: p1
- LineLineIntersection(x0, y0, x_1, y_1, x1, y1, x_2, y_2, ref p1);
- LineLineIntersection(x0, y0, x_1, y_1, x1, y1, x_5, y_5, ref p2);
- LineLineIntersection(x0, y0, x_6, y_6, x1, y1, x_2, y_2, ref p3);
- if ((p1[0] == 1.0) && (p2[0] == 1.0) && (p3[0] == 1.0))
- {
- // #0
- initialConvexPoly[0] = p1[1]; initialConvexPoly[1] = p1[2];
- // #1
- initialConvexPoly[2] = p2[1]; initialConvexPoly[3] = p2[2];
- // #2
- initialConvexPoly[4] = wedges[i * 20 + 12]; initialConvexPoly[5] = wedges[i * 20 + 13];
- // #3
- initialConvexPoly[6] = wedges[i * 20 + 8]; initialConvexPoly[7] = wedges[i * 20 + 9];
- // #4
- initialConvexPoly[8] = x3; initialConvexPoly[9] = y3;
- // #5
- initialConvexPoly[10] = wedges[i * 20 + 26]; initialConvexPoly[11] = wedges[i * 20 + 27];
- // #6
- initialConvexPoly[12] = wedges[i * 20 + 30]; initialConvexPoly[13] = wedges[i * 20 + 31];
- // #7
- initialConvexPoly[14] = p3[1]; initialConvexPoly[15] = p3[2];
- }
- break;
- case 10:
- // line1 & line2: p1
- LineLineIntersection(x0, y0, x_1, y_1, x1, y1, x_2, y_2, ref p1);
- LineLineIntersection(x0, y0, x_1, y_1, x1, y1, x_5, y_5, ref p2);
- LineLineIntersection(x0, y0, x_6, y_6, x1, y1, x_2, y_2, ref p3);
- //printf("p3 %f %f %f (%f %f) (%f %f) (%f %f) (%f %f)\n",p3[0],p3[1],p3[2], x0, y0, x_6, x_6, x1, y1, x_2, y_2);
- if ((p1[0] == 1.0) && (p2[0] == 1.0) && (p3[0] == 1.0))
- {
- // #0
- initialConvexPoly[0] = p1[1]; initialConvexPoly[1] = p1[2];
- // #1
- initialConvexPoly[2] = p2[1]; initialConvexPoly[3] = p2[2];
- // #2
- initialConvexPoly[4] = wedges[i * 20 + 16]; initialConvexPoly[5] = wedges[i * 20 + 17];
- // #3
- initialConvexPoly[6] = wedges[i * 20 + 12]; initialConvexPoly[7] = wedges[i * 20 + 13];
- // #4
- initialConvexPoly[8] = wedges[i * 20 + 8]; initialConvexPoly[9] = wedges[i * 20 + 9];
- // #5
- initialConvexPoly[10] = x3; initialConvexPoly[11] = y3;
- // #6
- initialConvexPoly[12] = wedges[i * 20 + 28]; initialConvexPoly[13] = wedges[i * 20 + 29];
- // #7
- initialConvexPoly[14] = wedges[i * 20 + 32]; initialConvexPoly[15] = wedges[i * 20 + 33];
- // #8
- initialConvexPoly[16] = wedges[i * 20 + 34]; initialConvexPoly[17] = wedges[i * 20 + 35];
- // #9
- initialConvexPoly[18] = p3[1]; initialConvexPoly[19] = p3[2];
- }
- break;
- }
- // printf("smallest edge (%f,%f) (%f,%f)\n", x0,y0, x1,y1);
- // printf("real INITIAL POLY [%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;]\n", initialConvexPoly[0],initialConvexPoly[1],initialConvexPoly[2],initialConvexPoly[3],initialConvexPoly[4],initialConvexPoly[5],initialConvexPoly[6],initialConvexPoly[7],initialConvexPoly[8],initialConvexPoly[9],initialConvexPoly[10],initialConvexPoly[11],initialConvexPoly[12],initialConvexPoly[13],initialConvexPoly[14],initialConvexPoly[15],initialConvexPoly[16],initialConvexPoly[17],initialConvexPoly[18],initialConvexPoly[19]);
- }
- x0 = x1; y0 = y1;
- x1 = x2; y1 = y2;
- }
- /// HALF PLANE INTERSECTION: START SPLITTING THE INITIAL POLYGON TO FIND FEASIBLE REGION
- if (numpoints != 0)
- {
- // first intersect the opposite located ones
- s = (numpoints - 1) / 2 + 1;
- flag = 0;
- count = 0;
- i = 1;
- num = howManyPoints;
- for (j = 0; j < 40; j = j + 4)
- {
- // in order to skip non-existent lines
- if (howManyPoints == 4 && (j == 8 || j == 12 || j == 16 || j == 24 || j == 28 || j == 32))
- {
- continue;
- }
- else if (howManyPoints == 6 && (j == 12 || j == 16 || j == 28 || j == 32))
- {
- continue;
- }
- else if (howManyPoints == 8 && (j == 16 || j == 32))
- {
- continue;
- }
- // printf("%d 1 INITIAL POLY [%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;]\n",num, initialConvexPoly[0],initialConvexPoly[1],initialConvexPoly[2],initialConvexPoly[3],initialConvexPoly[4],initialConvexPoly[5],initialConvexPoly[6],initialConvexPoly[7],initialConvexPoly[8],initialConvexPoly[9],initialConvexPoly[10],initialConvexPoly[11],initialConvexPoly[12],initialConvexPoly[13],initialConvexPoly[14],initialConvexPoly[15],initialConvexPoly[16],initialConvexPoly[17],initialConvexPoly[18],initialConvexPoly[19]);
- // printf("line (%f, %f) (%f, %f)\n",wedges[40*s+j],wedges[40*s+1+j], wedges[40*s+2+j], wedges[40*s+3+j]);
- numpolypoints = HalfPlaneIntersection(num, ref initialConvexPoly, wedges[40 * s + j], wedges[40 * s + 1 + j], wedges[40 * s + 2 + j], wedges[40 * s + 3 + j]);
- if (numpolypoints == 0)
- return false;
- else
- num = numpolypoints;
- }
- count++;
- //printf("yes here\n");
- while (count < numpoints - 1)
- {
- for (j = 0; j < 40; j = j + 4)
- {
- // in order to skip non-existent lines
- if (howManyPoints == 4 && (j == 8 || j == 12 || j == 16 || j == 24 || j == 28 || j == 32))
- {
- continue;
- }
- else if (howManyPoints == 6 && (j == 12 || j == 16 || j == 28 || j == 32))
- {
- continue;
- }
- else if (howManyPoints == 8 && (j == 16 || j == 32))
- {
- continue;
- }
- ////printf("%d 2 INITIAL POLY [%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;%.12f, %.12f;]\n",numpolypoints, initialConvexPoly[0],initialConvexPoly[1],initialConvexPoly[2],initialConvexPoly[3],initialConvexPoly[4],initialConvexPoly[5],initialConvexPoly[6],initialConvexPoly[7],initialConvexPoly[8],initialConvexPoly[9],initialConvexPoly[10],initialConvexPoly[11],initialConvexPoly[12],initialConvexPoly[13],initialConvexPoly[14],initialConvexPoly[15],initialConvexPoly[16],initialConvexPoly[17],initialConvexPoly[18],initialConvexPoly[19]);
- //printf("line (%.20f, %.20f) (%.20f, %.20f)\n", wedges[40 * (i + s * flag) + j], wedges[40 * (i + s * flag) + 1 + j], wedges[40 * (i + s * flag) + 2 + j], wedges[40 * (i + s * flag) + 3 + j]);
- numpolypoints = HalfPlaneIntersection(num, ref initialConvexPoly, wedges[40 * (i + s * flag) + j], wedges[40 * (i + s * flag) + 1 + j], wedges[40 * (i + s * flag) + 2 + j], wedges[40 * (i + s * flag) + 3 + j]);
- if (numpolypoints == 0)
- return false;
- else
- num = numpolypoints;
- }
- i = i + flag;
- flag = (flag + 1) % 2;
- count++;
- }
- /// IF THERE IS A FEASIBLE INTERSECTION POLYGON, FIND ITS CENTROID AS THE NEW LOCATION
- FindPolyCentroid(numpolypoints, initialConvexPoly, ref newloc);
- if (behavior.MaxAngle != 0.0)
- {
- numBadTriangle = 0;
- for (j = 0; j < numpoints * 2 - 2; j = j + 2)
- {
- if (IsBadTriangleAngle(newloc[0], newloc[1], points[j], points[j + 1], points[j + 2], points[j + 3]))
- {
- numBadTriangle++;
- }
- }
- if (IsBadTriangleAngle(newloc[0], newloc[1], points[0], points[1], points[numpoints * 2 - 2], points[numpoints * 2 - 1]))
- {
- numBadTriangle++;
- }
- if (numBadTriangle == 0)
- {
- return true;
- }
- n = (numpoints <= 2) ? 20 : 30;
- // try points other than centroid
- for (k = 0; k < 2 * numpoints; k = k + 2)
- {
- for (e = 1; e < n; e = e + 1)
- {
- newloc[0] = 0.0; newloc[1] = 0.0;
- for (i = 0; i < 2 * numpoints; i = i + 2)
- {
- weight = 1.0 / numpoints;
- if (i == k)
- {
- newloc[0] = newloc[0] + 0.1 * e * weight * points[i];
- newloc[1] = newloc[1] + 0.1 * e * weight * points[i + 1];
- }
- else
- {
- weight = (1.0 - 0.1 * e * weight) / (double)(numpoints - 1.0);
- newloc[0] = newloc[0] + weight * points[i];
- newloc[1] = newloc[1] + weight * points[i + 1];
- }
- }
- numBadTriangle = 0;
- for (j = 0; j < numpoints * 2 - 2; j = j + 2)
- {
- if (IsBadTriangleAngle(newloc[0], newloc[1], points[j], points[j + 1], points[j + 2], points[j + 3]))
- {
- numBadTriangle++;
- }
- }
- if (IsBadTriangleAngle(newloc[0], newloc[1], points[0], points[1], points[numpoints * 2 - 2], points[numpoints * 2 - 1]))
- {
- numBadTriangle++;
- }
- if (numBadTriangle == 0)
- {
- return true;
- }
- }
- }
- }
- else
- {
- //printf("yes, we found a feasible region num: %d newloc (%.12f,%.12f)\n", numpolypoints, newloc[0], newloc[1]);
- // for(i = 0; i < 2*numpolypoints; i = i+2){
- // printf("point %d) (%.12f,%.12f)\n", i/2, initialConvexPoly[i], initialConvexPoly[i+1]);
- // }
- // printf("numpoints %d\n",numpoints);
- return true;
- }
- }
- return false;
- }
- /// <summary>
- /// Check polygon for min angle.
- /// </summary>
- /// <param name="numpoints"></param>
- /// <param name="points"></param>
- /// <returns>Returns true if the polygon has angles greater than 2*minangle.</returns>
- private bool ValidPolygonAngles(int numpoints, double[] points)
- {
- int i;//,j
- for (i = 0; i < numpoints; i++)
- {
- if (i == numpoints - 1)
- {
- if (IsBadPolygonAngle(points[i * 2], points[i * 2 + 1], points[0], points[1], points[2], points[3]))
- {
- return false; // one of the inner angles is less than required
- }
- }
- else if (i == numpoints - 2)
- {
- if (IsBadPolygonAngle(points[i * 2], points[i * 2 + 1], points[(i + 1) * 2], points[(i + 1) * 2 + 1], points[0], points[1]))
- {
- return false; // one of the inner angles is less than required
- }
- }
- else
- {
- if (IsBadPolygonAngle(points[i * 2], points[i * 2 + 1], points[(i + 1) * 2], points[(i + 1) * 2 + 1], points[(i + 2) * 2], points[(i + 2) * 2 + 1]))
- {
- return false; // one of the inner angles is less than required
- }
- }
- }
- return true; // all angles are valid
- }
- /// <summary>
- /// Given three coordinates of a polygon, tests to see if it satisfies the minimum
- /// angle condition for relocation.
- /// </summary>
- /// <param name="x1"></param>
- /// <param name="y1"></param>
- /// <param name="x2"></param>
- /// <param name="y2"></param>
- /// <param name="x3"></param>
- /// <param name="y3"></param>
- /// <returns>Returns true, if it is a BAD polygon corner, returns false if it is a GOOD
- /// polygon corner</returns>
- private bool IsBadPolygonAngle(double x1, double y1,
- double x2, double y2, double x3, double y3)
- {
- // variables keeping the distance values for the edges
- double dx12, dy12, dx23, dy23, dx31, dy31;
- double dist12, dist23, dist31;
- double cosAngle; // in order to check minimum angle condition
- // calculate the side lengths
- dx12 = x1 - x2;
- dy12 = y1 - y2;
- dx23 = x2 - x3;
- dy23 = y2 - y3;
- dx31 = x3 - x1;
- dy31 = y3 - y1;
- // calculate the squares of the side lentghs
- dist12 = dx12 * dx12 + dy12 * dy12;
- dist23 = dx23 * dx23 + dy23 * dy23;
- dist31 = dx31 * dx31 + dy31 * dy31;
- /// calculate cosine of largest angle ///
- cosAngle = (dist12 + dist23 - dist31) / (2 * Math.Sqrt(dist12) * Math.Sqrt(dist23));
- // Check whether the angle is smaller than permitted which is 2*minangle!!!
- //printf("angle: %f 2*minangle = %f\n",acos(cosAngle)*180/PI, 2*acos(Math.Sqrt(b.goodangle))*180/PI);
- if (Math.Acos(cosAngle) < 2 * Math.Acos(Math.Sqrt(behavior.goodAngle)))
- {
- return true;// it is a BAD triangle
- }
- return false;// it is a GOOD triangle
- }
- /// <summary>
- /// Given four points representing two lines, returns the intersection point.
- /// </summary>
- /// <param name="x1"></param>
- /// <param name="y1"></param>
- /// <param name="x2"></param>
- /// <param name="y2"></param>
- /// <param name="x3"></param>
- /// <param name="y3"></param>
- /// <param name="x4"></param>
- /// <param name="y4"></param>
- /// <param name="p">The intersection point.</param>
- /// <remarks>
- // referenced to: http://local.wasp.uwa.edu.au/~pbourke/geometry/
- /// </remarks>
- private void LineLineIntersection(
- double x1, double y1,
- double x2, double y2,
- double x3, double y3,
- double x4, double y4, ref double[] p)
- {
- // x1,y1 P1 coordinates (point of line 1)
- // x2,y2 P2 coordinates (point of line 1)
- // x3,y3 P3 coordinates (point of line 2)
- // x4,y4 P4 coordinates (point of line 2)
- // p[1],p[2] intersection coordinates
- //
- // This function returns a pointer array which first index indicates
- // weather they intersect on one point or not, followed by coordinate pairs.
- double u_a, u_b, denom;
- // calculate denominator first
- denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
- u_a = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
- u_b = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
- // if denominator and numerator equal to zero, lines are coincident
- if (Math.Abs(denom - 0.0) < EPS && (Math.Abs(u_b - 0.0) < EPS && Math.Abs(u_a - 0.0) < EPS))
- {
- p[0] = 0.0;
- }
- // if denominator equals to zero, lines are parallel
- else if (Math.Abs(denom - 0.0) < EPS)
- {
- p[0] = 0.0;
- }
- else
- {
- p[0] = 1.0;
- u_a = u_a / denom;
- u_b = u_b / denom;
- p[1] = x1 + u_a * (x2 - x1); // not the intersection point
- p[2] = y1 + u_a * (y2 - y1);
- }
- }
- /// <summary>
- /// Returns the convex polygon which is the intersection of the given convex
- /// polygon with the halfplane on the left side (regarding the directional vector)
- /// of the given line.
- /// </summary>
- /// <param name="numvertices"></param>
- /// <param name="convexPoly"></param>
- /// <param name="x1"></param>
- /// <param name="y1"></param>
- /// <param name="x2"></param>
- /// <param name="y2"></param>
- /// <returns></returns>
- /// <remarks>
- /// http://www.mathematik.uni-ulm.de/stochastik/lehre/ws03_04/rt/Geometry2D.ps
- /// </remarks>
- private int HalfPlaneIntersection(int numvertices, ref double[] convexPoly, double x1, double y1, double x2, double y2)
- {
- double dx, dy; // direction of the line
- double z, min, max;
- int i, j;
- int numpolys;
- double[] res = null;
- int count = 0;
- int intFound = 0;
- dx = x2 - x1;
- dy = y2 - y1;
- numpolys = SplitConvexPolygon(numvertices, convexPoly, x1, y1, x2, y2, polys);
- if (numpolys == 3)
- {
- count = numvertices;
- }
- else
- {
- for (i = 0; i < numpolys; i++)
- {
- min = double.MaxValue;
- max = double.MinValue;
- // compute the minimum and maximum of the
- // third coordinate of the cross product
- for (j = 1; j <= 2 * polys[i][0] - 1; j = j + 2)
- {
- z = dx * (polys[i][j + 1] - y1) - dy * (polys[i][j] - x1);
- min = (z < min ? z : min);
- max = (z > max ? z : max);
- }
- // ... and choose the (absolute) greater of both
- z = (Math.Abs(min) > Math.Abs(max) ? min : max);
- // and if it is positive, the polygon polys[i]
- // is on the left side of line
- if (z > 0.0)
- {
- res = polys[i];
- intFound = 1;
- break;
- }
- }
- if (intFound == 1)
- {
- while (count < res[0])
- {
- convexPoly[2 * count] = res[2 * count + 1];
- convexPoly[2 * count + 1] = res[2 * count + 2];
- count++;
- }
- }
- }
- // update convexPoly
- return count;
- }
- /// <summary>
- /// Splits a convex polygons into one or two polygons through the intersection
- /// with the given line (regarding the directional vector of the given line).
- /// </summary>
- /// <param name="numvertices"></param>
- /// <param name="convexPoly"></param>
- /// <param name="x1"></param>
- /// <param name="y1"></param>
- /// <param name="x2"></param>
- /// <param name="y2"></param>
- /// <param name="polys"></param>
- /// <returns></returns>
- /// <remarks>
- /// http://www.mathematik.uni-ulm.de/stochastik/lehre/ws03_04/rt/Geometry2D.ps
- /// </remarks>
- private int SplitConvexPolygon(int numvertices, double[] convexPoly, double x1, double y1, double x2, double y2, double[][] polys)
- {
- // state = 0: before the first intersection (with the line)
- // state = 1: after the first intersection (with the line)
- // state = 2: after the second intersection (with the line)
- int state = 0;
- double[] p = new double[3];
- int poly1counter = 0;
- int poly2counter = 0;
- int numpolys;
- int i;
- double compConst = 0.000000000001;
- // for debugging
- int case1 = 0, case2 = 0, case3 = 0, case31 = 0, case32 = 0, case33 = 0, case311 = 0, case3111 = 0;
- // intersect all edges of poly with line
- for (i = 0; i < 2 * numvertices; i = i + 2)
- {
- int j = (i + 2 >= 2 * numvertices) ? 0 : i + 2;
- LineLineSegmentIntersection(x1, y1, x2, y2, convexPoly[i], convexPoly[i + 1], convexPoly[j], convexPoly[j + 1], ref p);
- // if this edge does not intersect with line
- if (Math.Abs(p[0] - 0.0) <= compConst)
- {
- //System.out.println("null");
- // add p[j] to the proper polygon
- if (state == 1)
- {
- poly2counter++;
- poly2[2 * poly2counter - 1] = convexPoly[j];
- poly2[2 * poly2counter] = convexPoly[j + 1];
- }
- else
- {
- poly1counter++;
- poly1[2 * poly1counter - 1] = convexPoly[j];
- poly1[2 * poly1counter] = convexPoly[j + 1];
- }
- // debug
- case1++;
- }
- // ... or if the intersection is the whole edge
- else if (Math.Abs(p[0] - 2.0) <= compConst)
- {
- //System.out.println(o);
- // then we can not reach state 1 and 2
- poly1counter++;
- poly1[2 * poly1counter - 1] = convexPoly[j];
- poly1[2 * poly1counter] = convexPoly[j + 1];
- // debug
- case2++;
- }
- // ... or if the intersection is a point
- else
- {
- // debug
- case3++;
- // if the point is the second vertex of the edge
- if (Math.Abs(p[1] - convexPoly[j]) <= compConst && Math.Abs(p[2] - convexPoly[j + 1]) <= compConst)
- {
- // debug
- case31++;
- if (state == 1)
- {
- poly2counter++;
- poly2[2 * poly2counter - 1] = convexPoly[j];
- poly2[2 * poly2counter] = convexPoly[j + 1];
- poly1counter++;
- poly1[2 * poly1counter - 1] = convexPoly[j];
- poly1[2 * poly1counter] = convexPoly[j + 1];
- state++;
- }
- else if (state == 0)
- {
- // debug
- case311++;
- poly1counter++;
- poly1[2 * poly1counter - 1] = convexPoly[j];
- poly1[2 * poly1counter] = convexPoly[j + 1];
- // test whether the polygon is splitted
- // or the line only touches the polygon
- if (i + 4 < 2 * numvertices)
- {
- int s1 = LinePointLocation(x1, y1, x2, y2, convexPoly[i], convexPoly[i + 1]);
- int s2 = LinePointLocation(x1, y1, x2, y2, convexPoly[i + 4], convexPoly[i + 5]);
- // the line only splits the polygon
- // when the previous and next vertex lie
- // on different sides of the line
- if (s1 != s2 && s1 != 0 && s2 != 0)
- {
- // debug
- case3111++;
- poly2counter++;
- poly2[2 * poly2counter - 1] = convexPoly[j];
- poly2[2 * poly2counter] = convexPoly[j + 1];
- state++;
- }
- }
- }
- }
- // ... if the point is not the other vertex of the edge
- else if (!(Math.Abs(p[1] - convexPoly[i]) <= compConst && Math.Abs(p[2] - convexPoly[i + 1]) <= compConst))
- {
- // debug
- case32++;
- poly1counter++;
- poly1[2 * poly1counter - 1] = p[1];
- poly1[2 * poly1counter] = p[2];
- poly2counter++;
- poly2[2 * poly2counter - 1] = p[1];
- poly2[2 * poly2counter] = p[2];
- if (state == 1)
- {
- poly1counter++;
- poly1[2 * poly1counter - 1] = convexPoly[j];
- poly1[2 * poly1counter] = convexPoly[j + 1];
- }
- else if (state == 0)
- {
- poly2counter++;
- poly2[2 * poly2counter - 1] = convexPoly[j];
- poly2[2 * poly2counter] = convexPoly[j + 1];
- }
- state++;
- }
- // ... else if the point is the second vertex of the edge
- else
- {
- // debug
- case33++;
- if (state == 1)
- {
- poly2counter++;
- poly2[2 * poly2counter - 1] = convexPoly[j];
- poly2[2 * poly2counter] = convexPoly[j + 1];
- }
- else
- {
- poly1counter++;
- poly1[2 * poly1counter - 1] = convexPoly[j];
- poly1[2 * poly1counter] = convexPoly[j + 1];
- }
- }
- }
- }
- // after splitting the state must be 0 or 2
- // (depending whether the polygon was splitted or not)
- if (state != 0 && state != 2)
- {
- // printf("there is something wrong state: %d\n", state);
- // printf("polygon might not be convex!!\n");
- // printf("case1: %d\ncase2: %d\ncase3: %d\ncase31: %d case311: %d case3111: %d\ncase32: %d\ncase33: %d\n", case1, case2, case3, case31, case311, case3111, case32, case33);
- // printf("numvertices %d\n=============\n", numvertices);
- // if there is something wrong with the intersection, just ignore this one
- numpolys = 3;
- }
- else
- {
- // finally convert the vertex lists into convex polygons
- numpolys = (state == 0) ? 1 : 2;
- poly1[0] = poly1counter;
- poly2[0] = poly2counter;
- // convert the first convex polygon
- polys[0] = poly1;
- // convert the second convex polygon
- if (state == 2)
- {
- polys[1] = poly2;
- }
- }
- return numpolys;
- }
- /// <summary>
- /// Determines on which side (relative to the direction) of the given line and the
- /// point lies (regarding the directional vector) of the given line.
- /// </summary>
- /// <param name="x1"></param>
- /// <param name="y1"></param>
- /// <param name="x2"></param>
- /// <param name="y2"></param>
- /// <param name="x"></param>
- /// <param name="y"></param>
- /// <returns></returns>
- /// <remarks>
- /// http://www.mathematik.uni-ulm.de/stochastik/lehre/ws03_04/rt/Geometry2D.ps
- /// </remarks>
- private int LinePointLocation(double x1, double y1, double x2, double y2, double x, double y)
- {
- double z;
- if (Math.Atan((y2 - y1) / (x2 - x1)) * 180.0 / Math.PI == 90.0)
- {
- if (Math.Abs(x1 - x) <= 0.00000000001)
- return 0;
- }
- else
- {
- if (Math.Abs(y1 + (((y2 - y1) * (x - x1)) / (x2 - x1)) - y) <= EPS)
- return 0;
- }
- // third component of the 3 dimensional product
- z = (x2 - x1) * (y - y1) - (y2 - y1) * (x - x1);
- if (Math.Abs(z - 0.0) <= 0.00000000001)
- {
- return 0;
- }
- else if (z > 0)
- {
- return 1;
- }
- else
- {
- return 2;
- }
- }
- /// <summary>
- /// Given four points representing one line and a line segment, returns the intersection point
- /// </summary>
- /// <param name="x1"></param>
- /// <param name="y1"></param>
- /// <param name="x2"></param>
- /// <param name="y2"></param>
- /// <param name="x3"></param>
- /// <param name="y3"></param>
- /// <param name="x4"></param>
- /// <param name="y4"></param>
- /// <param name="p"></param>
- /// <remarks>
- /// referenced to: http://local.wasp.uwa.edu.au/~pbourke/geometry/
- /// </remarks>
- private void LineLineSegmentIntersection(
- double x1, double y1,
- double x2, double y2,
- double x3, double y3,
- double x4, double y4, ref double[] p)
- {
- // x1,y1 P1 coordinates (point of line)
- // x2,y2 P2 coordinates (point of line)
- // x3,y3 P3 coordinates (point of line segment)
- // x4,y4 P4 coordinates (point of line segment)
- // p[1],p[2] intersection coordinates
- //
- // This function returns a pointer array which first index indicates
- // weather they intersect on one point or not, followed by coordinate pairs.
- double u_a, u_b, denom;
- double compConst = 0.0000000000001;
- // calculate denominator first
- denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
- u_a = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
- u_b = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
- //if(fabs(denom-0.0) < compConst && (fabs(u_b-0.0) < compConst && fabs(u_a-0.0) < compConst)){
- //printf("denom %.20f u_b %.20f u_a %.20f\n",denom, u_b, u_a);
- if (Math.Abs(denom - 0.0) < compConst)
- {
- if (Math.Abs(u_b - 0.0) < compConst && Math.Abs(u_a - 0.0) < compConst)
- {
- p[0] = 2.0; // if denominator and numerator equal to zero, lines are coincident
- }
- else
- {
- p[0] = 0.0;// if denominator equals to zero, lines are parallel
- }
- }
- else
- {
- u_b = u_b / denom;
- u_a = u_a / denom;
- // printf("u_b %.20f\n", u_b);
- if (u_b < -compConst || u_b > 1.0 + compConst)
- { // check if it is on the line segment
- // printf("line (%.20f, %.20f) (%.20f, %.20f) line seg (%.20f, %.20f) (%.20f, %.20f) \n",x1, y1 ,x2, y2 ,x3, y3 , x4, y4);
- p[0] = 0.0;
- }
- else
- {
- p[0] = 1.0;
- p[1] = x1 + u_a * (x2 - x1); // intersection point
- p[2] = y1 + u_a * (y2 - y1);
- }
- }
- }
- /// <summary>
- /// Returns the centroid of a given polygon
- /// </summary>
- /// <param name="numpoints"></param>
- /// <param name="points"></param>
- /// <param name="centroid">Centroid of a given polygon </param>
- private void FindPolyCentroid(int numpoints, double[] points, ref double[] centroid)
- {
- int i;
- //double area = 0.0;//, temp
- centroid[0] = 0.0; centroid[1] = 0.0;
- for (i = 0; i < 2 * numpoints; i = i + 2)
- {
- centroid[0] = centroid[0] + points[i];
- centroid[1] = centroid[1] + points[i + 1];
- }
- centroid[0] = centroid[0] / numpoints;
- centroid[1] = centroid[1] / numpoints;
- }
- /// <summary>
- /// Given two points representing a line and a radius together with a center point
- /// representing a circle, returns the intersection points.
- /// </summary>
- /// <param name="x1"></param>
- /// <param name="y1"></param>
- /// <param name="x2"></param>
- /// <param name="y2"></param>
- /// <param name="x3"></param>
- /// <param name="y3"></param>
- /// <param name="r"></param>
- /// <param name="p">Pointer to list of intersection points</param>
- /// <remarks>
- /// referenced to: http://local.wasp.uwa.edu.au/~pbourke/geometry/sphereline/
- /// </remarks>
- private void CircleLineIntersection(
- double x1, double y1,
- double x2, double y2,
- double x3, double y3, double r, ref double[] p)
- {
- // x1,y1 P1 coordinates [point of line]
- // x2,y2 P2 coordinates [point of line]
- // x3,y3, r P3 coordinates(circle center) and radius [circle]
- // p[1],p[2]; p[3],p[4] intersection coordinates
- //
- // This function returns a pointer array which first index indicates
- // the number of intersection points, followed by coordinate pairs.
- //double x , y ;
- double a, b, c, mu, i;
- a = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
- b = 2 * ((x2 - x1) * (x1 - x3) + (y2 - y1) * (y1 - y3));
- c = x3 * x3 + y3 * y3 + x1 * x1 + y1 * y1 - 2 * (x3 * x1 + y3 * y1) - r * r;
- i = b * b - 4 * a * c;
- if (i < 0.0)
- {
- // no intersection
- p[0] = 0.0;
- }
- else if (Math.Abs(i - 0.0) < EPS)
- {
- // one intersection
- p[0] = 1.0;
- mu = -b / (2 * a);
- p[1] = x1 + mu * (x2 - x1);
- p[2] = y1 + mu * (y2 - y1);
- }
- else if (i > 0.0 && !(Math.Abs(a - 0.0) < EPS))
- {
- // two intersections
- p[0] = 2.0;
- // first intersection
- mu = (-b + Math.Sqrt(i)) / (2 * a);
- p[1] = x1 + mu * (x2 - x1);
- p[2] = y1 + mu * (y2 - y1);
- // second intersection
- mu = (-b - Math.Sqrt(i)) / (2 * a);
- p[3] = x1 + mu * (x2 - x1);
- p[4] = y1 + mu * (y2 - y1);
- }
- else
- {
- p[0] = 0.0;
- }
- }
- /// <summary>
- /// Given three points, check if the point is the correct point that we are looking for.
- /// </summary>
- /// <param name="x1">P1 coordinates (bisector point of dual edge on triangle)</param>
- /// <param name="y1">P1 coordinates (bisector point of dual edge on triangle)</param>
- /// <param name="x2">P2 coordinates (intersection point)</param>
- /// <param name="y2">P2 coordinates (intersection point)</param>
- /// <param name="x3">P3 coordinates (circumcenter point)</param>
- /// <param name="y3">P3 coordinates (circumcenter point)</param>
- /// <param name="isObtuse"></param>
- /// <returns>Returns true, if given point is the correct one otherwise return false.</returns>
- private bool ChooseCorrectPoint(
- double x1, double y1,
- double x2, double y2,
- double x3, double y3, bool isObtuse)
- {
- double d1, d2;
- bool p;
- // squared distance between circumcenter and intersection point
- d1 = (x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3);
- // squared distance between bisector point and intersection point
- d2 = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
- if (isObtuse)
- {
- // obtuse case
- if (d2 >= d1)
- {
- p = true; // means we have found the right point
- }
- else
- {
- p = false; // means take the other point
- }
- }
- else
- {
- // non-obtuse case
- if (d2 < d1)
- {
- p = true; // means we have found the right point
- }
- else
- {
- p = false; // means take the other point
- }
- }
- /// HANDLE RIGHT TRIANGLE CASE!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- return p;
- }
- /// <summary>
- /// This function returns a pointer array which first index indicates the whether
- /// the point is in between the other points, followed by coordinate pairs.
- /// </summary>
- /// <param name="x1">P1 coordinates [point of line] (point on Voronoi edge - intersection)</param>
- /// <param name="y1">P1 coordinates [point of line] (point on Voronoi edge - intersection)</param>
- /// <param name="x2">P2 coordinates [point of line] (circumcenter)</param>
- /// <param name="y2">P2 coordinates [point of line] (circumcenter)</param>
- /// <param name="x">P3 coordinates [point to be compared] (neighbor's circumcenter)</param>
- /// <param name="y">P3 coordinates [point to be compared] (neighbor's circumcenter)</param>
- /// <param name="p"></param>
- private void PointBetweenPoints(double x1, double y1, double x2, double y2, double x, double y, ref double[] p)
- {
- // now check whether the point is close to circumcenter than intersection point
- // BETWEEN THE POINTS
- if ((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y) < (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
- {
- p[0] = 1.0;
- // calculate the squared distance to circumcenter
- p[1] = (x - x2) * (x - x2) + (y - y2) * (y - y2);
- p[2] = x;
- p[3] = y;
- }// *NOT* BETWEEN THE POINTS
- else
- {
- p[0] = 0.0;
- p[1] = 0.0;
- p[2] = 0.0;
- p[3] = 0.0;
- }
- }
- /// <summary>
- /// Given three coordinates of a triangle, tests a triangle to see if it satisfies
- /// the minimum and/or maximum angle condition.
- /// </summary>
- /// <param name="x1"></param>
- /// <param name="y1"></param>
- /// <param name="x2"></param>
- /// <param name="y2"></param>
- /// <param name="x3"></param>
- /// <param name="y3"></param>
- /// <returns>Returns true, if it is a BAD triangle, returns false if it is a GOOD triangle.</returns>
- private bool IsBadTriangleAngle(double x1, double y1, double x2, double y2, double x3, double y3)
- {
- // variables keeping the distance values for the edges
- double dxod, dyod, dxda, dyda, dxao, dyao;
- double dxod2, dyod2, dxda2, dyda2, dxao2, dyao2;
- double apexlen, orglen, destlen;
- double angle; // in order to check minimum angle condition
- double maxangle; // in order to check minimum angle condition
- // calculate the side lengths
- dxod = x1 - x2;
- dyod = y1 - y2;
- dxda = x2 - x3;
- dyda = y2 - y3;
- dxao = x3 - x1;
- dyao = y3 - y1;
- // calculate the squares of the side lentghs
- dxod2 = dxod * dxod;
- dyod2 = dyod * dyod;
- dxda2 = dxda * dxda;
- dyda2 = dyda * dyda;
- dxao2 = dxao * dxao;
- dyao2 = dyao * dyao;
- // Find the lengths of the triangle's three edges.
- apexlen = dxod2 + dyod2;
- orglen = dxda2 + dyda2;
- destlen = dxao2 + dyao2;
- // try to find the minimum edge and accordingly the pqr orientation
- if ((apexlen < orglen) && (apexlen < destlen))
- {
- // Find the square of the cosine of the angle at the apex.
- angle = dxda * dxao + dyda * dyao;
- angle = angle * angle / (orglen * destlen);
- }
- else if (orglen < destlen)
- {
- // Find the square of the cosine of the angle at the origin.
- angle = dxod * dxao + dyod * dyao;
- angle = angle * angle / (apexlen * destlen);
- }
- else
- {
- // Find the square of the cosine of the angle at the destination.
- angle = dxod * dxda + dyod * dyda;
- angle = angle * angle / (apexlen * orglen);
- }
- // try to find the maximum edge and accordingly the pqr orientation
- if ((apexlen > orglen) && (apexlen > destlen))
- {
- // Find the cosine of the angle at the apex.
- maxangle = (orglen + destlen - apexlen) / (2 * Math.Sqrt(orglen * destlen));
- }
- else if (orglen > destlen)
- {
- // Find the cosine of the angle at the origin.
- maxangle = (apexlen + destlen - orglen) / (2 * Math.Sqrt(apexlen * destlen));
- }
- else
- {
- // Find the cosine of the angle at the destination.
- maxangle = (apexlen + orglen - destlen) / (2 * Math.Sqrt(apexlen * orglen));
- }
- // Check whether the angle is smaller than permitted.
- if ((angle > behavior.goodAngle) || (behavior.MaxAngle != 0.00 && maxangle < behavior.maxGoodAngle))
- {
- return true;// it is a bad triangle
- }
- return false;// it is a good triangle
- }
- /// <summary>
- /// Given the triangulation, and a vertex returns the minimum distance to the
- /// vertices of the triangle where the given vertex located.
- /// </summary>
- /// <param name="newlocX"></param>
- /// <param name="newlocY"></param>
- /// <param name="searchtri"></param>
- /// <returns></returns>
- private double MinDistanceToNeighbor(double newlocX, double newlocY, ref Otri searchtri)
- {
- Otri horiz = default(Otri); // for search operation
- LocateResult intersect = LocateResult.Outside;
- Vertex v1, v2, v3, torg, tdest;
- double d1, d2, d3, ahead;
- //triangle ptr; // Temporary variable used by sym().
- Point newvertex = new Point(newlocX, newlocY);
- // printf("newvertex %f,%f\n", newvertex[0], newvertex[1]);
- // Find the location of the vertex to be inserted. Check if a good
- // starting triangle has already been provided by the caller.
- // Find a boundary triangle.
- //horiz.tri = m.dummytri;
- //horiz.orient = 0;
- //horiz.symself();
- // Search for a triangle containing 'newvertex'.
- // Start searching from the triangle provided by the caller.
- // Where are we?
- torg = searchtri.Org();
- tdest = searchtri.Dest();
- // Check the starting triangle's vertices.
- if ((torg.x == newvertex.x) && (torg.y == newvertex.y))
- {
- intersect = LocateResult.OnVertex;
- searchtri.Copy(ref horiz);
- }
- else if ((tdest.x == newvertex.x) && (tdest.y == newvertex.y))
- {
- searchtri.Lnext();
- intersect = LocateResult.OnVertex;
- searchtri.Copy(ref horiz);
- }
- else
- {
- // Orient 'searchtri' to fit the preconditions of calling preciselocate().
- ahead = predicates.CounterClockwise(torg, tdest, newvertex);
- if (ahead < 0.0)
- {
- // Turn around so that 'searchpoint' is to the left of the
- // edge specified by 'searchtri'.
- searchtri.Sym();
- searchtri.Copy(ref horiz);
- intersect = mesh.locator.PreciseLocate(newvertex, ref horiz, false);
- }
- else if (ahead == 0.0)
- {
- // Check if 'searchpoint' is between 'torg' and 'tdest'.
- if (((torg.x < newvertex.x) == (newvertex.x < tdest.x)) &&
- ((torg.y < newvertex.y) == (newvertex.y < tdest.y)))
- {
- intersect = LocateResult.OnEdge;
- searchtri.Copy(ref horiz);
- }
- }
- else
- {
- searchtri.Copy(ref horiz);
- intersect = mesh.locator.PreciseLocate(newvertex, ref horiz, false);
- }
- }
- if (intersect == LocateResult.OnVertex || intersect == LocateResult.Outside)
- {
- // set distance to 0
- //m.VertexDealloc(newvertex);
- return 0.0;
- }
- else
- { // intersect == ONEDGE || intersect == INTRIANGLE
- // find the triangle vertices
- v1 = horiz.Org();
- v2 = horiz.Dest();
- v3 = horiz.Apex();
- d1 = (v1.x - newvertex.x) * (v1.x - newvertex.x) + (v1.y - newvertex.y) * (v1.y - newvertex.y);
- d2 = (v2.x - newvertex.x) * (v2.x - newvertex.x) + (v2.y - newvertex.y) * (v2.y - newvertex.y);
- d3 = (v3.x - newvertex.x) * (v3.x - newvertex.x) + (v3.y - newvertex.y) * (v3.y - newvertex.y);
- //m.VertexDealloc(newvertex);
- // find minimum of the distance
- if (d1 <= d2 && d1 <= d3)
- {
- return d1;
- }
- else if (d2 <= d3)
- {
- return d2;
- }
- else
- {
- return d3;
- }
- }
- }
- }
- }
|