Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - (gile)

Pages: 1 2 3 [4] 5 6
46
.NET newbies / New AutoCAD .NET Training
« on: May 07, 2011, 10:49:08 AM »
Hi,

Autodesk provides a new 'AutoCAD .NET Training' for A2011 and A2012 (usable with Visual Studio 2008 or 2010).

Anouncement on Kean's blog: Through the Interface.

Download on Autodesk Developer Center.

47
Math and Geometry / Re: Convex Hull
« on: April 25, 2011, 09:26:17 PM »
I added a C# code using Linq: a more 'functional style' with C# (can be done with VB too).

48
Math and Geometry / Re: Convex Hull
« on: April 18, 2011, 10:06:52 AM »
Hi,

There's no similar function in AutoCAD, maybe in MAP or Civil, I don't know.

I thaught it was intersting to show how to use a functional style with F# and an imperative* one with C# (or VB) to solve the same problem.

* even if the use of a delegate with the Sort method is more a functional feature.

49
Math and Geometry / Convex Hull
« on: April 16, 2011, 04:43:08 PM »
Here're a C# and a F# implementation of the 'Graham's scan' algorythm to get the convex hull of a 2d points collection.

[EDIT: added a C# implementation using Linq]

C# (targeting NET Framework 2.0 which is the default for A2007 -> A2009).
Code: [Select]
using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace ConvexHull
{
    public class Commands
    {
        private Point2d _p0;

        private bool Clockwise(Point2d p1, Point2d p2, Point2d p3)
        {
            return ((p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X)) < 1e-9;
        }

        private int ComparePoints(Point2d p1, Point2d p2)
        {
            if (p1.IsEqualTo(p2)) return 0;
            double d1 = _p0.GetDistanceTo(p1);
            double d2 = _p0.GetDistanceTo(p2);
            if (d1 == 0.0) return -1;
            if (d2 == 0.0) return 1;
            double cos = (p2.X - _p0.X) / d2 - (p1.X - _p0.X) / d1;
            if (cos < -1e-9) return -1;
            if (cos > 1e-9) return 1;
            return d1.CompareTo(d2);
        }

        private List<Point2d> ConvexHull(List<Point2d> pts)
        {
            _p0 = pts[0];
            for (int i = 1; i < pts.Count; i++)
            {
                Point2d pt = pts[i];
                if (pt.Y < _p0.Y || (pt.Y == _p0.Y && pt.X < _p0.X))
                    _p0 = pt;
            }
            pts.Sort(ComparePoints);
            for (int i = 1; i < pts.Count - 1; i++)
            {
                while (i > 0 && Clockwise(pts[i - 1], pts[i], pts[i + 1]))
                {
                    pts.RemoveAt(i);
                    i--;
                }
            }
            return pts;
        }

        [CommandMethod("ch", CommandFlags.UsePickSet)]
        public void testCh()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            TypedValue[] filter = new TypedValue[1] { new TypedValue(0, "POINT") };
            PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter));
            if (psr.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (Polyline pline = new Polyline())
            {
                List<Point2d> pts = new List<Point2d>();
                foreach (SelectedObject so in psr.Value)
                {
                    DBPoint dbPt = (DBPoint)tr.GetObject(so.ObjectId, OpenMode.ForRead);
                    pts.Add(new Point2d(dbPt.Position.X, dbPt.Position.Y));
                }
                for (int i = 0; i < ConvexHull(pts).Count; i++)
                {
                    pline.AddVertexAt(i, pts[i], 0.0, 0.0, 0.0);
                }
                pline.Closed = true;
                pline.SetDatabaseDefaults();
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                btr.AppendEntity(pline);
                tr.AddNewlyCreatedDBObject(pline, true);
                tr.Commit();
            }
        }
    }
}

C# (using Linq, NET Framework 3 or upper required)
Code: [Select]
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace LinqConvexHull
{
    public class Commands
    {
        private Point2d _p0;

        private bool Clockwise(Point2d p1, Point2d p2, Point2d p3)
        {
            return ((p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X)) < 1e-9;
        }

        private double Cosine(Point2d pt)
        {
            double d = _p0.GetDistanceTo(pt);
            return d == 0.0 ? 1.0 : Math.Round((pt.X - _p0.X) / d, 9);
        }

        private List<Point2d> ConvexHull(List<Point2d> pts)
        {
            _p0 = pts.OrderBy(p => p.Y).ThenBy(p => p.X).First();
            pts = pts.OrderByDescending(p => Cosine(p)).ThenBy(p => _p0.GetDistanceTo(p)).ToList();
            for (int i = 1; i < pts.Count - 1; i++)
            {
                while (i > 0 && Clockwise(pts[i - 1], pts[i], pts[i + 1]))
                {
                    pts.RemoveAt(i);
                    i--;
                }
            }
            return pts;
        }

        [CommandMethod("Test")]
        public void Test()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            TypedValue[] filter = new TypedValue[1] { new TypedValue(0, "POINT") };
            PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter));
            if (psr.Status != PromptStatus.OK) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (Polyline pline = new Polyline())
            {
                List<Point2d> pts = new List<Point2d>();
                foreach (SelectedObject so in psr.Value)
                {
                    DBPoint dbPt = (DBPoint)tr.GetObject(so.ObjectId, OpenMode.ForRead);
                    pts.Add(new Point2d(dbPt.Position.X, dbPt.Position.Y));
                }
                pts = ConvexHull(pts);
                for (int i = 0; i < pts.Count; i++)
                {
                    pline.AddVertexAt(i, pts[i], 0.0, 0.0, 0.0);
                }
                pline.Closed = true;
                pline.SetDatabaseDefaults();
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                btr.AppendEntity(pline);
                tr.AddNewlyCreatedDBObject(pline, true);
                tr.Commit();
            }
        }
    }
}

F#
Code: [Select]
module ConvexHull

open Autodesk.AutoCAD.ApplicationServices
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
open Autodesk.AutoCAD.Runtime

type AcAp = Autodesk.AutoCAD.ApplicationServices.Application

let clockwise (p1:Point2d) (p2:Point2d) (p3:Point2d) =
    (p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X) < 1e-9
   
let convexHull (pts : Point2d seq) =
    let rec fill acc pt =
        match acc with
        | a :: b :: _ when clockwise b a pt -> fill acc.Tail pt
        | _ -> pt :: acc
    let p0 = pts
             |> Seq.reduce (fun p1 p2 ->
                if p2.Y < p1.Y || (p1.Y = p2.Y && p2.X < p1.X) then p2 else p1)
    pts
    |> List.ofSeq
    |> List.sortBy (fun p ->
        let d = p0.GetDistanceTo(p)
        (Math.Round((p0.X - p.X) / d, 8), d))
    |> List.fold fill []
    |> List.rev

[<CommandMethod("ch")>]
let Test() =
    let doc = AcAp.DocumentManager.MdiActiveDocument
    let db = doc.Database
    let ed = doc.Editor
    let psr = ed.GetSelection(new SelectionFilter([| new TypedValue(0, "POINT") |]))
    if psr.Status = PromptStatus.OK then
        use tr = db.TransactionManager.StartTransaction()
        use pl = new Polyline()
        psr.Value
        |> Seq.cast<_>
        |> Seq.map (fun (so : SelectedObject) ->
            let pt = tr.GetObject(so.ObjectId, OpenMode.ForRead) :?> DBPoint
            new Point2d(pt.Position.X, pt.Position.Y))
        |> convexHull
        |> List.fold(fun i p ->  pl.AddVertexAt(i, p, 0.0, 0.0, 0.0); i + 1) 0
        |> ignore
        pl.Closed <- true
        pl.SetDatabaseDefaults()
        let btr = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) :?> BlockTableRecord
        btr.AppendEntity(pl) |> ignore
        tr.AddNewlyCreatedDBObject(pl, true)
        tr.Commit()

target audience:{advanced}

50
Blocks / Get block references in layouts only
« on: March 24, 2011, 11:05:28 PM »
Hi

The BlockTableRecord.GetBlockReferencesIds() method returns all inserted references, even nested in other blocks.

A way to get only references inserted in layout is to filter the ObjectIdCollection returned by GetBlockReferencesIds() with the reference owner.

The following F# and C# snippets define a function/method which require as arguments the database and the block name.
They return respectively an ObjectId array and an ObjectIdCollection which contain all block references directly inserted in layouts (even dynamic/anonymous blocks).

C#
Code: [Select]
        private ObjectIdCollection GetReferences(Database db, string bName)
        {
            ObjectIdCollection result = new ObjectIdCollection();
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt =
                    (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (bt.Has(bName))
                {
                    BlockTableRecord btr =
                        (BlockTableRecord)tr.GetObject(bt[bName], OpenMode.ForRead);
                    foreach (ObjectId refId in btr.GetBlockReferenceIds(true, false))
                    {
                        BlockReference br =
                            (BlockReference)tr.GetObject(refId, OpenMode.ForRead);
                        BlockTableRecord owner =
                            (BlockTableRecord)tr.GetObject(br.OwnerId, OpenMode.ForRead);
                        if (owner.IsLayout)
                            result.Add(br.ObjectId);
                    }
                    foreach (ObjectId id in btr.GetAnonymousBlockIds())
                    {
                        BlockTableRecord anon =
                            (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
                        foreach (ObjectId refId in anon.GetBlockReferenceIds(true, false))
                        {
                            BlockReference br =
                                (BlockReference)tr.GetObject(refId, OpenMode.ForRead);
                            BlockTableRecord owner =
                                (BlockTableRecord)tr.GetObject(br.OwnerId, OpenMode.ForRead);
                            if (owner.IsLayout)
                                result.Add(br.ObjectId);
                        }
                    }
                }
                tr.Commit();
            }
            return result;
        }

F#
Code: [Select]
let GetBlockReferences (db : Database) (bName : string) =
    use tr = db.TransactionManager.StartTransaction()
    let bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) :?> BlockTable
    if bt.Has(bName) then
        let btr = tr.GetObject(bt.[bName], OpenMode.ForRead) :?> BlockTableRecord
        btr.GetAnonymousBlockIds()
        |> Seq.cast<_>
        |> Seq.map (fun id -> tr.GetObject(id, OpenMode.ForRead) :?> BlockTableRecord)
        |> Seq.append (Seq.singleton btr)
        |> Seq.collect (fun b ->
            b.GetBlockReferenceIds(true, false)
            |> Seq.cast<_>
            |> Seq.filter (fun id ->
                let br = tr.GetObject(id, OpenMode.ForRead)
                let owner = tr.GetObject(br.OwnerId, OpenMode.ForRead) :?> BlockTableRecord
                owner.IsLayout))
        |> Seq.toArray
    else Array.empty

51
.NET newbies / Re: How can i view an ACAD file using DOTNET
« on: February 10, 2011, 11:47:08 AM »
Hi,

You have to to reference at least acdbmgd.dll and acmgd.dll
Have a look at:
http://docs.autodesk.com/ACD/2010/ENU/AutoCAD%20.NET%20Developer%27s%20Guide/index.html


52
Math and Geometry / Re: Geometry extensions
« on: February 03, 2011, 11:11:16 AM »
Hi,

Added some extension methods:

void Point2dCollection.RemoveDuplicate()
void Point2dCollection.RemoveDuplicate(Tolerance tol)
bool Point2dCollection.Contains(Point2d pt, Tolerance tol)

void Point3dCollection.RemoveDuplicate()
void Point3dCollection.RemoveDuplicate(Tolerance tol)
bool Point3dCollection.Contains(Point3d pt, Tolerance tol)

And edit the Triangle2d and Triangle3d classes:
both inherits from a 'generic' abstract class: Triangle<T> and have two new properties : CircumscribedCircle and InscribedCircle

53
This site / Re: Testing code highlighting
« on: December 15, 2010, 01:18:19 PM »
Appologies for my poor English.
I didn't want to say colorisation is a gadget in a code editor, but I think it is in a web site and according to what i saw in some other web sites (and what your saying), it seems it may not always work well: I saw some characters ('[', ']', '&', ...) displayed in html format.

Just my opinion...

54
This site / Re: Testing code highlighting
« on: December 15, 2010, 07:27:57 AM »
Hi,

IMO, there's no nedd for this kind of gadget which often provides more inconvinients than advantages.

I'd rather post/read non colorized full and right code than colorized one with syntax errors and/or restrictions.

Every one here is able to copy and paste a piece of code in its favorite code editor...

55
AutoCAD talk / LispFunction with autoCAD 2008
« on: December 06, 2010, 08:34:11 PM »
Hi,

A .NET defined LISP function (with the LispFunction attribute) can return any type of value available in LISP : string, int, double,Point3d,  SelectionSet, ObjectId (ename), TypedValue (T or nil), ResultBuffer (list)...

But it seems there's a bug with AutoCAD 2008 which only allows .NET defined LISP functions to return a ResulBuffer (a list or nil).

56
Selection sets / Selection Set Filters
« on: December 04, 2010, 10:24:53 PM »
In the .NET environment, a SelectionFilter is constructed with a TypedValue array.
A TypedValue can contain various Objects types in its Value property. The Object type is defined in the TypeCode property as an integer (or a DxfCode enum integer) which corresponds to the DXF group code of the Value.
For those who know AutoLISP, a TypedValue looks like a DXF dotted pair (even it is not the same thing, a dotted pair is a LISP specific data).
For the Values which type is String as entity type (DxfCode.Start = 0) or layer (DxfCode.Layer = 8), the Value can contain many patterns separted by commas and use wildcard patterns.
The filter can contain relational tests for the numerical values and logical grouping.

The more complete documentation in the AutoCAD Developer's Help for building sofisticated SelectionFilters is in the AutoLISP Help:
AutoLISP developer's Guide > Using the AutoLISP Language > Using AutoLISP to Manipulate AutoCAD Objects > Selection Set Handling > Selection Set Filter Lists
And the DXF group codes can be found in DXF Reference.

Here's an example to select closed polylines (lw, 2d and 3d) and closed ellipses on layers BASE and CONSTRUCTION

Code: [Select]
TypedValue[] filter =
            {   new TypedValue(-4, "<OR"),
                new TypedValue(-4, "<AND"),
                new TypedValue(0, "*POLYLINE"), // LWPOLYLINE and POLYLINE
                new TypedValue(-4, "&"),
                new TypedValue(70, 1), // Closed
                new TypedValue(-4, "<NOT"),
                new TypedValue(-4, "&"),
                new TypedValue(70, 112),  // Avoid meshes (bit codes: 16 + 32 + 64)
                new TypedValue(-4, "NOT>"),
                new TypedValue(-4, "AND>"),
                new TypedValue(-4, "<AND"),
                new TypedValue(0, "ELLIPSE"),
                new TypedValue(-4, "="),
                new TypedValue(41, 0.0), // Start parameter
                new TypedValue(-4, "="),
                new TypedValue(42, 6.283185307179586), // End parameter
                new TypedValue(-4, "AND>"),
                new TypedValue(-4, "OR>"),
                new TypedValue(8, "BASE,CONSTRUCTION")};
SelectionFilter = new SelectionFilter(filter);

target audience:{beginner}

57
Display / Zoom Objects
« on: December 04, 2010, 12:47:34 AM »
Hi,

Here's a little sample to make a Zoom on selected objects

<Edit: removed some unusefull statements>

C#
Code: [Select]
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

namespace ZoomObjectSample
{
    public class Zoom
    {
        [CommandMethod("ZO")]
        public void ZO()
        {
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptSelectionResult psr = ed.GetSelection();
            if (psr.Status != PromptStatus.OK)
                return;
            ObjectIdCollection idCol = new ObjectIdCollection(psr.Value.GetObjectIds());
            ZoomObjects(idCol);
        }

        private void ZoomObjects(ObjectIdCollection idCol)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            using (ViewTableRecord view = ed.GetCurrentView())
            {
                Matrix3d WCS2DCS = Matrix3d.PlaneToWorld(view.ViewDirection);
                WCS2DCS = Matrix3d.Displacement(view.Target - Point3d.Origin) * WCS2DCS;
                WCS2DCS = Matrix3d.Rotation(-view.ViewTwist, view.ViewDirection, view.Target) * WCS2DCS;
                WCS2DCS = WCS2DCS.Inverse();
                Entity ent = (Entity)tr.GetObject(idCol[0], OpenMode.ForRead);
                Extents3d ext = ent.GeometricExtents;
                for (int i = 1; i < idCol.Count; i++)
                {
                    ent = (Entity)tr.GetObject(idCol[i], OpenMode.ForRead);
                    Extents3d tmp = ent.GeometricExtents;
                    ext.AddExtents(tmp);
                }
                ext.TransformBy(WCS2DCS);
                view.Width = ext.MaxPoint.X - ext.MinPoint.X;
                view.Height = ext.MaxPoint.Y - ext.MinPoint.Y;
                view.CenterPoint =
                    new Point2d((ext.MaxPoint.X + ext.MinPoint.X) / 2.0, (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0);
                ed.SetCurrentView(view);
                tr.Commit();
            }
        }
    }
}

F#
Code: [Select]
module ZoomObjects

open Autodesk.AutoCAD.ApplicationServices
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
open Autodesk.AutoCAD.Runtime

let zoomObjects (ids : ObjectId[]) =
    let doc = Application.DocumentManager.MdiActiveDocument
    let db = doc.Database
    let ed = doc.Editor
    use tr = db.TransactionManager.StartTransaction()
    use view = ed.GetCurrentView()
   
    let getEnt id = tr.GetObject(id, OpenMode.ForRead) :?> Entity
   
    let addExts (ext : Extents3d) id =
        ext.AddExtents((getEnt id).GeometricExtents)
        ext
       
    let ext = ids |> Array.fold addExts (getEnt ids.[0]).GeometricExtents
    let WCS2DCS =  Matrix3d
                    .PlaneToWorld(view.ViewDirection)
                    .PreMultiplyBy(Matrix3d.Displacement(view.Target - Point3d.Origin))
                    .PreMultiplyBy(Matrix3d.Rotation(-view.ViewTwist, view.ViewDirection, view.Target))
                    .Inverse()
    ext.TransformBy(WCS2DCS)
    view.Width <- ext.MaxPoint.X - ext.MinPoint.X
    view.Height <- ext.MaxPoint.Y - ext.MinPoint.Y
    view.CenterPoint <- new Point2d((ext.MaxPoint.X + ext.MinPoint.X) / 2.0, (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0)
    ed.SetCurrentView(view)
    tr.Commit();

[<CommandMethod("ZO")>]
let zo() =
    let ed = Application.DocumentManager.MdiActiveDocument.Editor
    let psr = ed.GetSelection()
    if psr.Status = PromptStatus.OK then
        psr.Value.GetObjectIds() |> zoomObjects

VB
Code: [Select]
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.Runtime

Namespace ZoomObjectSample
Public Class Zoom
<CommandMethod("ZO")> _
Public Sub ZO()
Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
Dim psr As PromptSelectionResult = ed.GetSelection()
If psr.Status <> PromptStatus.OK Then
Return
End If
Dim idCol As New ObjectIdCollection(psr.Value.GetObjectIds())
ZoomObjects(idCol)
End Sub

Private Sub ZoomObjects(idCol As ObjectIdCollection)
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor
Using tr As Transaction = db.TransactionManager.StartTransaction()
Using view As ViewTableRecord = ed.GetCurrentView()
Dim WCS2DCS As Matrix3d = Matrix3d.PlaneToWorld(view.ViewDirection)
WCS2DCS = Matrix3d.Displacement(view.Target - Point3d.Origin) * WCS2DCS
WCS2DCS = Matrix3d.Rotation(-view.ViewTwist, view.ViewDirection, view.Target) * WCS2DCS
WCS2DCS = WCS2DCS.Inverse()
Dim ent As Entity = DirectCast(tr.GetObject(idCol(0), OpenMode.ForRead), Entity)
Dim ext As Extents3d = ent.GeometricExtents
For i As Integer = 1 To idCol.Count - 1
ent = DirectCast(tr.GetObject(idCol(i), OpenMode.ForRead), Entity)
Dim tmp As Extents3d = ent.GeometricExtents
ext.AddExtents(tmp)
Next
ext.TransformBy(WCS2DCS)
view.Width = ext.MaxPoint.X - ext.MinPoint.X
view.Height = ext.MaxPoint.Y - ext.MinPoint.Y
view.CenterPoint = New Point2d((ext.MaxPoint.X + ext.MinPoint.X) / 2.0, (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0)
ed.SetCurrentView(view)
tr.Commit()
End Using
End Using
End Sub
End Class
End Namespace

target audience:{intermediate}

58
This site / Re: Welcome on the AutoCAD .NET developpers forums
« on: December 03, 2010, 10:04:47 AM »
Hi Oleg,

Quote
Prog expertise: Beginner
If your prog expertise is "Beginner", what should I choose for mine ?!

Glad to see here some guys whom I learn much of my actual .NET little knowledge :clinoeil:

59
F# language / Expert F#, chapter 3
« on: November 28, 2010, 08:55:47 AM »
You can download the Chapter3 of "Expert F#" (Don Syme, Adam Granicz, Antonio Cisternino) called: "Introducing Functional Programming".

60
F# language / An Introduction to Microsoft F#
« on: November 28, 2010, 12:06:50 AM »
Another video of Luca Bolognese here which explains the basics of F# with a succulent Italian accent.


target audience:{beginner}

Pages: 1 2 3 [4] 5 6