Analitička geometrija i C# programiranje dio 4/n


Problem 5: Potrebno je pronaći najkraću udaljenost između tačke i prave.

shortestpointLine

Iz analitičke geometrije znamo da je najkraća udaljenost između prave i tačke ona udaljenost koja se poklapa sa pravom koja prolazi tačkom A i normalna je na pravu p.  U tom smislu pretpostavimo da normala povučena iz tačke A siječe pravu p u tački A’ . Posmatrajmo vektore \vec{P_{1}A} i \vec{P_{1}P_{2}'} .

Izračunavanjem vektorskog proizvoda ova dva vektora dobićemo površinu paralelograma razapetog na tim vektorima. Kako znamo da je površina paralelograma u našem slučaju: P=AA’ x P1P2, to lahko možemo izračunati dužinu stranice AA’. U stvari ona predstavlja visinu paralelograma.

Sada možemo pisati:

AA' = \frac{P1A x P1P2}{|P1A|}. Ovim smo izračunali najkraću udaljenost između tačke i prave. Implementacija u C# programskom jeziku moze izgledati na sljedeći način:

static float shortestDistance(Point A, Point P1, Point P2)
{
    //referentni vektor ili pravac kroz referentne tačke na pravoj
    Point vektor = new Point();
    vektor.x = P2.x - P1.x;
    vektor.y = P2.y - P1.y;

    //Pravimo vektor od referentne tacke 1 i date tacke a
    Point vektor2 = new Point();
    vektor2.x = P1.x - A.x;
    vektor2.y = P1.y - A.y;

    //Izračunavamo vektorski proizvod dva verktora
    float vecProd = vektor.y * vektor2.x - vektor.x * vektor2.y;
    //Izračunavamo modul vektora P1P2
    float mod1=(float)Math.Sqrt(vektor.x * vektor.x + vektor.y * vektor.y);

    //udaljenost d== vektorski proizvod/dizina vektora P1P2
    float dist = vecProd / mod1;

    return dist;
}
Advertisements

Analitička geometrija i C# programiranje dio 3/n


Problem 3 i 4: Pripadnost tačke kružnici ili pravilnom poligonu

 

tacka_u_kruznici tacka_u_poligonu

 

Implementacija problema pripadnosti tačke u kružnici je vrlo prosta i zahtjeva samo provjeru da li je dužina centra kružnice do posmatrane tačke manja ili jednaka radijusu kružnice. Implementacija se može napisati na sljedeci način:

/// <summary>
/// provjerava da i se tačka nalazi u kružnici
/// </summary>
/// <param name="a">koordinate tačke </param>
/// <param name="o1">koordinate centra kružnice</param>
/// <param name="radius">radijus kružnica</param>
/// <returns></returns>
bool isInCircle(Point a, Point o1, float radius)
{
    float length = (float)Math.Sqrt((a.x - o1.x) * (a.x - o1.x) + (a.y - o1.y) * (a.y - o1.y));

    if (radius >= length)
        return true;
    else
        return false;
}

Implementacija problema tačke u pravilnom poligonu je malo komplikovanija, a bazira se na činjenici da u koliko je tačka unutar poligona, tada tačka mora biti sa desne strane svih njegovih stranica, u koliko se stranica obilaze u smjeru kretanja kazaljke na satu. Implementacija izgleda kao na sljedećem listingu:

/// <summary>
/// vraća true ako se tačka A nalazi u poligonu
/// </summary>
/// <param name="a"></param>
/// <param name="o1">centar poligona</param>
/// <param name="polyedges">tačke tjemena poligona poredane u smjeru kretanja kazaljke na satu.</param>
/// <returns></returns>
bool isInPolygon(Point a, Point o1, Point[]polyedges)
{
    for (int i = 0; i < polyedges.Length; i++)
    {
        int j = i++;
        if (j == polyedges.Length)
            j = 0;
        if (isOnRightSide(a, polyedges[i], polyedges[j])==-1)
            return false;
    }
    return true;
}

Iz zadnjeg listinga vidimo da smo koristili metodu isOnRightSide iz prethodnog posta.

Configuring Visual Studio 2013 to use Git as Source Control


Visual Studio 2013 has ability to integrate Git source control. The blog post will shows in details how to configure Visual Studio to use Git, with remote repository at git.com. Configuration can be divided in several parts.

1. Installing required softwares

2. Creating SSH key and uploading to Git server

3. Configuring local Git repository and sync with remote server

4. Check in and check out source code.

Installing Git Extensions

Only software you have to install is Git Extensions for Windows which you can find on: http://code.google.com/p/gitextensions/

1. After you download Git Extension installer, start the installation process. The following images show  step during the installation process.

gitblog_inst_sl1
gitblog_inst_sl3
gitblog_inst_sl2
gitblog_inst_sl4

At this step,in some case you can get the error in the installation with the following message:

‘Installation directory must be on local hard drive’

In that case, open Command Prompt with Administrator priviledge, go to folder GitInstaller is downloaded and type the following command:

msiexec /i GitExtensions.msi WIXUI_DONTVALIDATEPATH=”1″ 

where GitExtension.msi is the name of your installer.

Continue with installation:

gitblog_inst_sl7
gitblog_inst_sl5
gitblog_inst_sl6

Now proceed with installation of two installers: KDiff and GIT. Follow the default setup options:

gitblog_inst_sl20

gitblog_inst_sl14

Finish the installation process:

gitblog_inst_sl22

gitblog_inst_sl21

 

Creating SSH key and uploading to Git server

After you installed Git Extension open the Git Extention from Desktop :

Put UserName and Email to login information:

gitblog_inst_sl23

gitblog_inst_sl24

 

By clicking on OK button, Git Extension displays start screen. From Tools menu choose  Git Bash command line tool to create SSH key.

 

gitblog_inst_sl25

 

From the picture below follow the instruction how to create SSH Key.

type: ssh-keygen -t rsa -C email@company.com, and press enter 4 times. By pressing Enter you accept default options.

gitblog_inst_sl27

 

After you create the key, you have to add it to local agent.

1. First start local agent: exec ssh-agent Bash   (eval `ssh-agent -s`)

2. Type ssh-add ~/.ssh/id_rsa

gitblog_inst_sl28

Add SSH key to GitHub

1. Open you Git Hub account

2. Go to Settings

3. Add SSH Tab

4. Press AddKey

5. Copy the Content of the id_rsa.pub (see picture below)

 

6. Paste to GitHub SSH key tab

gitblog_inst_sl30

You can test your account by typing ssh-T git@github.com to command line.

gitblog_inst_sl31

Now you are ready to use GitHub Source control.

Configuring local Git repository and sync with remote server

 

1. Define local repository path: C:/tfs/Git

2. Open GitExtensions: Open local repository:

gitblog_inst_sl32

 

2. Initialize local repository

 

gitblog_inst_sl33

 

Setup Remote Repository by specifing Name and SSH path of the project:

gitblog_inst_sl34

 

By pressing Save Changes from the last image, you setp the project and it is ready to be opened in Visula Studio.

Open Visual Studio 2013

Add local repository to Git

Double click on the project to get solution file to open:

gitblog_inst_sl35

Analitička geometrija i C# programiranje dio 2/n


U prethodnom dijelu smo dali osnovne teorijske osnove za implementaciju problema analitičke geometrije.

Problem 2: Pripadnost tačke kružnom segmentu?

tacka_u_kruznom_segmentu
Posmatrajmo gornju sliku na kojoj imamo kružni isječak, iz kojeg su povučene zrake z1 i z2. Pretpostavimo također da imamo tačku A koja se nalazi u kružnom isječku, dok tačka B se nalazi izvan isječka. Da bi odredili pripadnost tačke kružnom isječku potrebno je provjeriti sljedeće:

1. da se tačka nalazi s desne strane zrake z1

2. da se tačka nalazi sa lijeve strane zrake z2

3. da je dužina iz centra isječka do tačke A manja ili jednaka od radijusa kružnog isječka.

U koliko su sva tri uslova ispunjena, tada se tačka nalazi u kružnom isječku.

Kako smo već u prethodnom postu implementirali metodu za određivanje strane tačke, potrebno je još samo implementirati 3 slučaj.

/// <summary>
///
/// </summary>
/// <param name="a">posmatrana tačka</param>
/// <param name="o1">centar kruđnog isječka</param>
/// <param name="radius">radijus kružnog isječka</param>
/// <returns>tru ako je duzina manja od radijusa</returns>
bool isLessThanRadius(Point a, Point o1, float radius)
{
    float length= (float)Math.Sqrt((a.x-o1.x)*(a.x-o1.x) + (a.y-o1.y)*(a.y-o1.y));

    if (radius >= length)
        return true;
    else
        return false;
}

Na kraju je potrebno implementirati metodu koja će objediniti sva tri slučaja u vratiti true ako sva tri slučaja vrate true, u protivnom će vratiti false.

Ostavlja se čitaocu da sublimira prethodnu i ovu implementaciju shodno zaključcima.

Analitička geometrija i C# programiranje dio 1/n


Analitička geometrija

Iz matematike znamo da analitička geometrija predstavlja algebarski način opisivanja Euklidove geometrije. U analitičkoj geometriji pojmovi Euklidove geometrije se definišu na algebarski način. Prije konkretnih implementacija određenih problema analitičke geometrije, ponovimo na brzinu osnovne principe na kojim se temelji analitička geometrija.

Tačka

Osnovu analitičke geometrije čini koordinatni sistemi, koji mogu biti pravougli, polarni, sferni koordinatni sastem. Svakoj tački u euklidovom prostoru može se pridružiti jedna i samo jedna tačka koordinatnog sistema.

Npr. tačku A u analitičkoj geometriji možemo predstaviti kao:

A(x,y,z),

gdje x,y,z predstavljaju realne brojeve, koje zovemo još i koordinate.

Tačku A možemo predstaviti i preko polarnog (cilindričnog ) koordinatnog sistema kao:

A(r,\rho,z),

gdje su r,\rho,z – koordinate tačke.

Prava

Prava u Euklidovoj geometriji predstavlja osnovni pojam, a u analitičkoj geometriji se definiše preko jednačine prave. Najčešći oblik jednačine prave u analitičkoj geometriji prikazujemo na sljedeći način:

y=ax+b.

Jednačin prave u prostoru definišemo kao:

\frac{(x-x_0)} {a}=\frac{(y-y_0)} {b}=\frac{(z-z_0)} {c}..

Vektor

U analitičkoj geometriji vektor se definiše kao usmjerena duž. Npr.u koliko imamo dvije tačke A(x_A,y_A) i B(x_B,y_B), vektor \vec{AB} predstavlja usmjerenu duž čiji je početak u tački A a kraj u tački B.

\vec{AB} nije isto što i \vec{BA}.

U analitičkoj geometriji vektor se definiše kao:

\vec{AB}= (x_B-x_A, y_B-y_A)

Operacije nad vektorima

Kao što je poznato operacije nad vektorima se razliku od operacija nad brojevima odnosno skalarima. U koliko želimo da saberemo dva vektora \vec{a} i \vec{b} to možemo uraditi preko pravila:
1.Paralelograma i
2. Trougla.

Skalarni proizvod dva vektora

Skalarni proizvod dva vektora predstavlja proizvod dužine prvog i drugog vektora pomnožen sa kosinusom ugla koje vektori međusobno zatvaraj ili:

\vec{a} \dot \vec{b}= |a|\dot |b| cos (\alpha)

Vektorski proizvod dva vektora

Predstavlja jednu od najznačajniji osobina u analitičkoj geometriji, kao i kompjuterskoj grafici.
Vektorski proizvod predstavlja novi vektor:

  1. čija dužina predstavlja proizvod dužina vektora pomnožen sa sinusom ugla kojeg zatvaraju,
  2. pravac novog vektora okomit je na ravan kojeg čine vektori,
  3. smijer novog vektora se određuje pravilom desne ruke ili desnog koordinatnog sistema.
220px-Right_hand_rule_cross_product.svg

Određivanje smijera vektorskog proizvoda

U koliko imamo vektore \vec{a} i \vec{b} koji su definisani kao: \vec{a}(x_1,y_1,z_1) i \vec{b}(x_2,y_2,z_2), vektorski proizvod definišemo kao:

\vec{c}=\vec{a}\bigotimes \vec{b}=\begin{bmatrix} i & j & k\\ x_1 & y_1 & z_1\\ x_2 & y_2 & z_2 \end{bmatrix}

Primjeri

Problem 1: Položaj tačke u odnosu na pravu p

Pretpostavimo da imamo pravu p i tačku A koja nije kolinearna s pravom p. Potrebno je implementirati algoritam koji će dati odgovor na pitanje s koje strane se ona nalazi. Da bi riješili ovaj problem potrebno je iskoristiti osobinu vektorskog proizvoda dva vektora. Potrebno je napomenuti da je smijer gledanja duž prave važan u definisanju stane. U protivnom ne bi smo znali koja je lijeva, a koja desna strana.

Pretpostavimo da imamo situaciju kao na donjoj slici. Također primjetimo da smo označili smijer gledanaj duž prave p. Uočimo dvije tačke na pravoj p, P1 i P2. Da bi odrediti s koje strane se nalazi tačka A, prvo trebamo formirati vektor \vec(P_1P_2), a zatim vektor \vec(P_1A). Na kraju je potrebno izračunati njihov vektorski proizvod. Primjetimo da nam je P_1  početna tačka za oba vektora shodno pretpostavljenom smijeru gledanja duž prave.

tacka_s_sastrane_prave

 

U koliko sada primjenimo pravilo određivanja smijera vektorskog proizvoda (vidi gore sliku) možemo riješiti problem.  U koliko poznajemo koordinate tačke A, odnosno tačaka P1 i P2 te izračunamo vrijednost vektorskog proizvoda.

Pozitivan rezultat vektorskog proizvoda odgovorit će nam na pitanje  da li je tačka sa desne strane, dok će negativna vrijednost indicirati da se tačka nalazi s lijeve strane.

U koliko dobijemo proizvod nula, to znači se tačka A nalazi na pravoj p, odnosno da je kolinearna sa pravom p.

class Point
{
    public float x;
    public float y;
    public float z;
    public Point() { }
    public Point(float xx, float yy, float zz)
    {
        x = xx;
        y = yy;
        z = zz;
    }
}
/// <summary>
/// da li je tačka s desne strane prave
/// </summary>
/// <param name="A">tačka</param>
/// <param name="p1">početna tačka na pravoj p</param>
/// <param name="p2">krajnja tačka na pravoj p</param>
/// <returns>1 tačka s desne strane, -1 tačka s lijeve strane, 0 tačka na pravoj p.</returns>
static int isOnRightSide(Point A, Point p1, Point p2)
{
    //referentni vektor ili pravac kroz referentne tačke na pravoj
    Point vektor = new Point();
    vektor.x = p2.x - p1.x;
    vektor.y = p2.y - p1.y;

    //Pravimo vektor od referentne tacke 1 i date tacke a
    Point vektor2= new Point();
    vektor2.x = A.x - p1.x;
    vektor2.y = A.y - p1.y;

    //Izračunavamo vektorski proizvod dva verktora
    //ako je prozvod veći od nule tada je tačka s desne strane prave p

    float rezultat = vektor.y * vektor2.x - vektor.x * vektor2.y;

    if (rezultat > 0)
        return 1;//tačka se nalazi s desne strane
    else if (rezultat < 0)
        return -1;//tačka se nalazi s lijeve strane
    else
        return 0; //tačka lezi na pravoj p
}

Drag and Drop Item Outside WPF Application


In WFP applications drag and drop functionality is provided by subscribing several events. First of all you need LeftMouseButtonClick and MouseMove events in order to start Drag and Drop.

This is accomplished by the following code:

private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    this._startPoint = e.GetPosition(null);
}

private void Window_MouseMove(object sender, MouseEventArgs e)
{
    //drag is heppen
    //Prepare for Drag and Drop
    Point mpos = e.GetPosition(null);
    Vector diff = this._startPoint - mpos;

    if (e.LeftButton == MouseButtonState.Pressed &&
        (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
        Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
    {

        //hooking on Mouse Up
        InterceptMouse.m_hookID = InterceptMouse.SetHook(InterceptMouse.m_proc);

        //ataching the event for hadling drop
        this.QueryContinueDrag += queryhandler;
        //begin drag and drop
        DataObject dataObj = new DataObject(this.text1);
        DragDrop.DoDragDrop(this.text1, dataObj, DragDropEffects.Move);

    }
}

As we can see from the code above, first with LeftMouseButtonClick event, we captured the starting point, then by MouseMove event, calculated distance between starting point and the current mouse position. If the distance is big enough we start DragDrop.

When the Drag starts it is necessary to prepare Drag functionality by providing the object to be dragged. In our case (code sample above) we are going to drag TextBox. In order to drag TextBox first we create DragData object by specifying TextBox object in the Constructor, and call DragDrop static method by passing objects we mentioned.
Beside preparing data to be dragged, we need to subscribe to QueryContinueDrag event in order to track dragging status.

This is all we need to prepare Drag and Drop in our application. If we want to drag object out of WPF aplication, we have no enough information to accomplish drop. As soon as the mouse is outside the app, mousemove event is not firing any more. One of the solution of the problem could be capturing the mouse move position outside the WFP application, and when the left mouse button is up, start with dropping item functionality.

In order to track mouse position outside the WPF application we need to hook and subscribe to the messages of whole Windows OS and filter only we are interesting in. Great blog post about how to capture  mouse messages regardless of the  mouse position can be found here.

Implementation of Low Level Mouse Hook in C# blog post can be modified quickly in order to adopt to our case.

First we need a property to indicate when the mouse is outside the application.

public static bool IsMouseOutsideApp 
{
    get;
    set;
}

Then we need to modify HookCallback method so that when the Left mouse button is up, and set the property (IsMouseOutsideApp ) to true if the mouse outside the application.

internal static IntPtr HookCallback( int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode >= 0 && MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
    {
        MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));

        //check if POint in main window
        Point pt = new Point(hookStruct.pt.x, hookStruct.pt.y);
        var ptw = App.Current.MainWindow.PointFromScreen(pt);
        var w = App.Current.MainWindow.Width;
        var h = App.Current.MainWindow.Height;
        //if point is outside MainWindow
        if (ptw.X < 0 || ptw.Y < 0 || ptw.X > w || ptw.Y > h)
            IsMouseOutsideApp = true;
        else
            IsMouseOutsideApp = false;
    }
    return CallNextHookEx(m_hookID, nCode, wParam, lParam);
}

The Last thing we need to implement is DragSourceQueryContinueDrag event. The implementation is straightforward:
1. check the keystate value None – this is the case when the mouse is released.
2. unhook from the mouse intercepting messages
3. show the message text based on the result of drag and dropping.

 
/// <summary>
/// Continuosly tracking Dragging mouse position
/// </summary>
/// 
/// 
private void DragSourceQueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
    //when keystate is non, draop is heppen
    if (e.KeyStates == DragDropKeyStates.None)
    {
        //unsubscribe event
        this.QueryContinueDrag -= queryhandler;
        e.Handled = true;
        //Unhooking on Mouse Up
        InterceptMouse.UnhookWindowsHookEx(InterceptMouse.m_hookID);

        //notifiy user about drop result
        Task.Run(
            () =>;
            {
                //Drop hepend outside Instantly app
                if (InterceptMouse.IsMouseOutsideApp)
                    MessageBox.Show("Dragged outside app");
                else
                    MessageBox.Show("Dragged inside app");
            }
            );
    }
}

Complete demo with source code can be found here:

Using TaskCompletionSource in wraping event handler


Using TaskCompletionSource you can wrap any operation in to task, so that you can do anything you can with the task object. The TaskCompletionSource class is very important and today’s post will be explain how to wrap button click event in to TaskCompletionSource. With this wrap we will see how complicated operation behind click button handler can be simplified.

The for this blog post is simple Windows Store app shown on the picture below.

screen_sample2

When the Play Slides is clicked, Image slide is started which start animation of images. XAML code behind this app is listed here:

<Page.Resources>
    <Storyboard x:Name="animImageSlideIn">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
                                        Storyboard.TargetName="img">
            <EasingDoubleKeyFrame KeyTime="0" Value="900"/>
            <EasingDoubleKeyFrame KeyTime="0:0:2" Value="0" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Width="200" Height="250" >
        <Button x:Name="playbtn" Height="50" Margin="0,5,0,5" Content="Play Slides" HorizontalAlignment="Center" Click="playbtn_Click"></Button>

        <Image x:Name="img" HorizontalAlignment="Center">
            <Image.RenderTransform>
                <CompositeTransform TranslateY="900" />
            </Image.RenderTransform>
        </Image>
    </StackPanel>
</Grid>

First, it will be presented  the implementation without TaskCompletionSource. The Play Slides Click event is the following code:

private async void  playbtn_Click(object sender, RoutedEventArgs e)
{
    int i = 1;

    EventHandler<object> handler = null;

    handler = delegate
    {
        if (i <= 3)
        {
            playbtn.Content = string.Format("Slide Image {0}",i);

            LoadSourceImage(i);

            animImageSlideIn.Begin();

            i++;
        }
        else
        {
            playbtn.Content = "Play Slides";
            animImageSlideIn.Completed -= handler;
            LoadSourceImage(0);

        }
    };

    animImageSlideIn.Completed += handler;
    handler(null,null);
}

As we can see from the listing above the code is pretty much long and little bit confused because we subscribe to the handler and call it as much as we reach the magic number of slides. Whe the number of slides is reached we unsubscribed from the handler and exit  the method.

Now implement the same functionality with the TaskCompletionSource class. The following listing shows the implementation:

private async void playbtn_Click(object sender, RoutedEventArgs e)
{

for(int i=1; i<=3; i++)
{
playbtn.Content = string.Format("Slide Image {0}",i);
LoadSourceImage(i);
await animImageSlideIn.RunAsync();
}

playbtn.Content = "Play Slides";
}

As we can see the implementation is very simple and concise. in for loop we call LoadSourceImage then asynchrony run animation.

The source code of the demo can be found by clicking the image below:

This blog post is inspired by Stephen Toub //build/ session.