วันจันทร์ที่ 17 ธันวาคม พ.ศ. 2555

สร้างเสาเป็น Element แรกใน Revit

เพื่อเป็นกำลังใจในการเริ่มเขียนโปรแกรมใน Revit
ก็จะเริ่มจากการเขียน เสา ไปใน Revit โดยง่ายที่สุด (แต่ก็เอาเรื่องเหมือนกัน)
วิธีการ จะต้องเข้าใจก่อนว่า เราต้องมี Family ก็ไปทำการ Load Family จาก Library ของ Revit ใน Project มาก่อน จากนั้น ใน โปรแกรม ก็จะคิดว่าเราได้ นำ Family ต่างๆ และกำหนด Type ต่างๆ มาแล้ว

เริ่มจาก 
1. เริ่มเปิด Document ก่อน และต้องเปิด Trasaction (เป็นระบบเดียวกับ ฐานข้อมูลที่เราสามารถยกเลิกได้ โดยไม่ทำให้โปรแกรม หรือข้อมูลเสียหาย)

Autodesk.Revit.DB.Document document = commandData.Application.ActiveUIDocument.Document;


FilteredElementCollector collector = new FilteredElementCollector(document);
 Transaction tr = new Transaction(CachedDoc);

          if (TransactionStatus.Started == tr.Start("Create Columns"))
          {.. ที่ต้องการทำ ..

          tr.Commit();  // ปิด transaction และ update revit
       }



2. ใส่ส่วน "ที่ต้องการทำ" ทำการ กรองเฉพาะ Family ที่ต้องการโดยเลือกจากCatalog -> Structure Columns


Collection<Element> fmList = collector.OfClass(typeof(FamilySymbol)).ToElements();
 var query = from fm1 in fmList where ((FamilySymbol)fm1).Category.Name == "Structural Columns" select (FamilySymbol)fm1;
    List<FamilySymbol> oFmList = query.ToList<FamilySymbol>();

จะเห็นได้ว่ามีความแตกต่างจาก บทความก่อนหน้านี้นะครับ ผมใช้ Linq ในการกรองข้อมูลซึ่งเท่ากับ การใช้ Foreach เกือบ 10 บรรทัด โดยกรองเฉพาะ "Structural Columns" ใส่ใน oFmList

ตอนนี้เราจะมี Family ที่เป็น Array เพื่อเลือกใช้งาน แล้ว

3.ทำการวาด ได้แก่ การกำหนด ElementSet และ กำหนด ตำแหน่ง แล้วสร้าง Instance หรือวาง
สำหรับการสร้าง จะมีการกำหนดเมื่อมีการสร้าง Element ว่าต้องเป็น StructuralType.Column ส่วนนี้บังคับ จะต้องมีหมวด ตาม Revit กำหนดซึ่งมาจาก IFC Standard(ระบบมาตรฐานของ Bim) 

ElementSet elementSet = null;
for (int i = 1; i < 7; i++)
            {
            int k = i % oFmList.Count;
            FamilySymbol sFm = oFmList[k];

                  XYZ location = new XYZ(i * 10, 100, 0);
                  FamilyInstanceCreationData fiCreationData = new FamilyInstanceCreationData(location, sFm, level,
                              Autodesk.Revit.DB.Structure.StructuralType.Column);
                  if (null != fiCreationData)
                  {
                        fiCreationDatas.Add(fiCreationData);
                  }
            }
           
if (fiCreationDatas.Count > 0)
  {     
   elementSet = document.Create.NewFamilyInstances(fiCreationDatas);
  }

เมื่อ Compile แล้วทดสอบ ก็จะวาง เสาตาม Family และ Type ต่างๆตามในรูป









หา RevitApi และ Revit Sdk ได้ที่ใหน

บังเอิญว่ามีอาจาร์ยที่รู้จักกันสนใจต้องการแนะนำเริ่มเขียน C# บน Revit  อยากทราบว่า จะไปหา SDK ตัวอย่างได้ที่ใหน ผมก็ลืมใส่ใว้ใน Post ก่อนหน้า
ไปที่นี่ครับ

http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=2484975

หรือ ใช้ Google search "revitsdk download"
ก็จะ Link มาที่นี้เช่นกัน
สำหรับข้อเขียนของตัวอย่างที่ Advance หน่อยก็ไปที่

http://thebuildingcoder.typepad.com


สำหรับการ ลง จะเป็นการแตกไฟล์ ที่ Pack มา ก็จะสร้างเป็น Folder

โดยตัวอย่างจะอยู่ใน Sample และที่สำคัญต้องลง Add-In Manager ที่อยู่ใน Folder ดังรูปก่อน จึงจะ ทำการ Load Add-in ตามตัวอย่างได้ สำหรับ Compiler ใช้ Visual Studio 2010 Professional ขึ้นไปหรือ Express (Free) ก็ได้ ไปที่

 http://www.microsoft.com/visualstudio/eng/downloads

โปรแกรมที่ Compile แล้วจะได้เป็น <โปรแกรม>.dll จะนำมาใช้งาน จะใช้ Load และแสดงเป็นคำสั่ง

ถ้าต้องการทดสอบโปรแกรมก็ให้กด Run

เทคนิคอยู่นิดหนึ่งคือเมื่อสั่ง Save ใน Dialog Add-in แล้ว ต้องออกจาก Revit แล้วมาเข้าไหม่จะมี เมนูใน Add-in ปรากฏขึ้น เมื่อเข้าใหม่


การจัดการของ Family ใน Revit


การจัดการของ Family ใน Revit
อ.ธนะพันธ์ อินทรเกสร
ระบบ Family ใน Revit เป็นส่วนสำคัญมาก ที่ทำให้ Revit ใช้งานง่าย ใน การจัดการ ของ Revit จะมี โครงสร้าง  3 ส่วน ได้แก่
1. Category     จะบอกว่าเป็นหมวดของงานอะไร เช่น เป็นงานหลังคาก็ได้แก่ Roofs หรือ โครงสร้างเช่น Structural Beam Systems เป็นต้น
2. Family  ได้แก่ สัญญลักษณ์ 3 มิติ หรือ 2 มิติ รูปของวัตถุนั้นเช่น เสา Concrete หรือ เสา I beam เป็นต้น
3. Family Type เป็นการตั้งค่า ของ Family ให้มีชื่อและขนาดตาม Parameter ตามต้องการ


4. Instances เป็น วัตถุ ในแบบที่เกิดจาก Family ที่เลือกมา โดยจะมี Id เฉพาะ ไม่ซ้ำ
จะเห็นว่าตัวแปรใน วัตถุจะมี 2 สถานะ ใน Instance จะเป็นตัวแปรเฉพาะตัว ส่วน type จะเป็นตัวแปรทั้งหมดใน type เดียวกัน

เพื่อสร้างโปรแกรมในการทำงาน อัตโนมัติ จะต้องนำ Family มาใช้ ต้องเข้าใจว่าใน แบบหรือ project ที่ทำงานของ Revit จะเรียกว่า Document ที่จะบรรจุ Family เป็น Element (แบบเดียวกัน กับ Block ใน Autocad และทุกอย่างใน Revit จะเรียกว่า Element) การมาใช้งาน จะสร้าง Instance (แบบเดียวกับ BlockRefence ใน Autocad)
การขั้นแรก Scan ทั้ง Document ใส่ใน Array

Autodesk.Revit.DB.Document document = commandData.Application.ActiveUIDocument.Document;

FilteredElementCollector collector = new FilteredElementCollector(document);


Collector จะมี ทุก Element ใน Project ปัจจุบัน ทั้ง Element ที่มองเห็น ทั้ง View ทุกอย่าง เพื่อให้เหลือเฉพาะส่วนที่ต้องการการ เราจะต้องทำการ filter หรือกรอง เฉพาะ Family โดยจะเรียกว่า FamilySymbol
      ICollection<Element> collection = collector.OfClass(typeof(FamilySymbol)).ToElements();

ตอนนี้เราจะได้ Family มาทั้งหมดแล้วใน collection ถ้าเราต้องการเฉพาะ
Category ใน Code จะเป็น
collection[i].Category.Name
ลองเขียนเป็นโปรแกรม
foreach (Element e in collection)
    {
        familySymbol = e as FamilySymbol;

        MessageBox.Show(familySymbol.Category.Name);
        Family fm = familySymbol.Family;
                   MessageBox.Show (fm.Name);

        ElementType et = e as ElementType;

        if (null != familySymbol.Category)
        {
            if ("Structural Columns" == familySymbol.Category.Name)
            {
 MessageBox.Show (et.Name);

                break;
            }
        }
    }

สำหรับการแสดงชื่อของ Family จะใช้
Family fm = familySymbol.Family;
                   MessageBox.Show (fm.Name);
โดยที่  familySymbol จะเก็บทัง Category และ Family
แต่ การที่จะเข้าไปใน Type จำเป็นต้องใช้ ElementType ในการ Cast Element เพื่อที่จะนำค่า
ElementType มาใช้งาน
 ถ้าต้องการ Type ก็ใช้
ElementType et = e as ElementType;
  MessageBox.Show (et.Name);

Revit ใช้การเขียนโปรแกรมในระบบที่ทันสมัยมาก ได้ใช้ Linq ทำให้การเขียนโปรแกรมสั้นลงไปอย่างมาก
ผมจะแนะนำในตอนหน้า



วันพฤหัสบดีที่ 6 กันยายน พ.ศ. 2555

เรื่องของ BIM ด้วย Revit

ในการเขียนโปรแกรม BIM กำลังเป็นเรื่องที่ Hot ในวงการ CAD AEC โปรแกรมที่มีคนใช้งานจำนวนมาก ได้แก่ Revit ของ Autodesk ซึ่งเป็นผู้ผลิตโปรแกรม Autocad อันมีชื่อเสียงมานาน และ Archicad ในค่าย ยุโรป ผมขอเริ่มที่ Revit ก่อน


สำหรับการเขียน แบบด้วย Revit จะเรียกว่า เขียนคงจะไม่ใช่น่าจะเป็นการสร้างแบบจำลอง อาคาร
หรือ Model จะดีกว่า เพราะการเขียนแบบ จะเป็นการวาดเส้น ซึ่งไม่ใช่ใน Revit หลักการของโปรแกรมใน  โปรแกรม BIM ให้คิดเสียว่าเป็นการ จำลองวัตถุ เข้าไปใน Space 3มิติ  แต่ทำไมในวงการสถาปนิก กับ วิศวกรรม ก่อสร้าง ยังไม่แพร่หลายอย่างที่ควร ถ้าดูจาก Vesion ของRevit ปัจจุบัน ก็ 2013 ถ้านับที่เริ่มรู้จักกันในเมืองไทย ก็ Revit 2009  ประมาณ 4-5 ปี ยังมีผู้ใช้งานไม่มากนัก เท่าที่ควร  อะไรคือปัญหา
ถ้าเราดูวิธีการทำงานในแบบ

แบบแปลนของ อาคาร ที่เราเขียน จะใช้ สัญญลักษณ์ ที่เรียกว่า Block และ เส้นต่างๆ ให้ ความหมาย เช่น กำแพง เป็นเส้นคู่ หน้าต่างประตูก็ใช้ สัญญลักษณ์ และมี Tag กำกับ  ถ้าคนเขียนเป็น ใน Autocad จะใช้เวลาไม่เกิน 15 นาที่ ก็สามารถ ทำแบบ นี้ได้ 
ที่นี้ไปดูใน โปรแกรม Bim เช่น Revit ในการสร้างกำแพง จะต้องบอก คุณสมบัติในการวางวัตถุ เช่น ความสูงจากพื้น ความหนากำแพง และวัสดุที่ใช้ รวมทั้งระยะ ชั้น 2 ด้วย

ตอนวาดไม่เป็นไร แต่ต้องกำหนดข้อมูลแยะ นี่ คนวาด ไม่ชอบแล้วต้องคิดแยะ ก่อนทำ
แต่ก็มีข้อดีคือ เมื่อวาด เป็น 3D จะแปลงรูปเป็น 2D ก็ไม่ยากทั้งแปลนและรูปด้าน และ เปลี่ยนแบบ 3D จะแปลงเป็น2D ได้เช่นกัน

แต่ถ้านำไปใช้ในงานก่อสร้าง หรือขออนุญาติ ได้หรือยัง ยังอีกพอสมควรครับ ต้องเขียนแบบ 2D 
อีก อันนี้ทำให้หลายคนที่ใช้ พบว่าโปรแกรมไม่ทำงานแบบเบ็ดเสร็จ ต้องกลับไป ระหว่าง Autocad กับ Revit (ความจริง Revit เขียนแบบ 2D ได้ครับ แต่ไม่เก่งเท่า Autocad)  แต่อย่างไรก็ดี Revit Bim ก็ให้ข้อมูลที่สำคัญหลายอย่าง เช่น นำ้หนัก วัสดุ การเชื่อมต่อเช่น คาน เสา เป็นต้น อันไปใช้ในการคำนวน และ การวางแผนได้หลายอย่าง อันนี้ ต้องเขียน โปรแกรมกัน ซึ่งผมจะเริ่มอธิบายขั้นตอน ที่จะทำให้ การใช้  BIM ทำงานแบบ อัตโนมัติในการสร้าง แบบ 2มิติ และไปคำนวนด้วย Revit เป็นโปรแกรมที่ทันสมัยในการเขียนโปรแกรมหลายอย่าง ที่ผมจะอธิบายใน Post ต่อไป


Tag:  เรียน Bim, Bim ศิลปากร, เขียนโปรแกรม Revit, Revit API



วันพฤหัสบดีที่ 21 มิถุนายน พ.ศ. 2555

การนำ C# มาใช้งาน กับ Ruby C/C++ ภาคที่ 2 ติดต่อกับRuby


-Thanaphan In.
ในบทที่แล้ว ได้แนะนำการใช้งานที่ ให้สร้าง C# เป็น Com Interface สำหรับให้ โปรแกรม อื่นใน window สามารถ ติดต่อกันได้ ได้ สำหรับ การใช้งาน กับ ภาษา Ruby ไม่ว่าจะเป็น  Sketchup หรือ Ruby on Rail ก็สามารถใช้งานได้ 2 ทาง คือ ผ่าน Interface ของ C/C++ หรือ ผ่าน “win32ole” สำหรับ win32ole มีตัวอย่างบน Internet พอสมควรแล้ว(ค้นใน Google “ruby win32ole”) สำหรับ การใช้ C/C++ มีขอที่ดีคือสามารถใช้ Debuger ของ Visual Studio ดูระหว่างทำงานได้ เพื่อสะดวกการสร้าง เป็น Class Interface ระหว่าง C++ กับ C# การเขียนโปรแกรมจะได้ ใช้ Visual Studio เป็นส่วนใหญ่

ไปที่ตัวอย่างที่สร้าง Dialog บน MFC สร้างปุ่มกด
Add C#  และมี EditBox  ตามรูป


สำหรับหัวไฟล์ ให้ใส่เพิ่ม #import

#include "stdafx.h"
#include "winsock.h"
#include "ruby.h"
#include "rbMfc1.h"
#include "rbDlgMFC1.h"
#include "rubyutils.h"

#import "Mathlib.tlb" raw_interfaces_only




ที่ EditBox add Variable ด้วยกดเมาวส์ขวา ชื่อ c_Edit1
สร้างคำสั่งสำหรับปุ่มแรก

void CtestCallManageDlg::OnBnClickedButton1()
{
      // TODO: Add your control notification handler code here
    HRESULT hr= CoInitialize(NULL); // เริ่ม Interface
MathLib::IAddClassPtr pIAddClass(__uuidof(CAddClass));//คลาสใน C#
        long result=0;
        hr=pIAddClass->Add(10,20,&result);//Function ใน Interface C#
       
        CoUninitialize();// จบ Interface
        CString outt;
        outt.Format(_T("%d"),result);
        this->c_Edit1.SetWindowTextW(outt);
}



สำหรับ Form ให้ สร้างอีกปุ่ม (การสร้างให้กด double Click ที่ปุ่ม)
void CtestCallManageDlg::OnBnClickedButton2()
{
      // TODO: Add your control notification handler code here
 HRESULT hr= CoInitialize(NULL);

 MathLib::IForm1Ptr pIForm(__uuidof(CiForm1));
        long result=0;
         hr= pIForm->aForm(&result);//Function ในการเรียก Form
        CoUninitialize();
        CString outt;
     
        outt.Format(_T("%d"),result);
       // this->c_Edit1.SetWindowTextW(outt);

}


จากนั้น Build และทำการ Copy Mathlib.dll ไปที่ google..\plugins ไม่นั้นจะทำงานไม่ได้




วันอังคารที่ 19 มิถุนายน พ.ศ. 2555

สร้าง Application บน Sketchup ด้วย C# ภาคที่1 C# COM

ในบทก่อนหน้านี้ ผมได้แนะนำการใช้ MFC C/C++ ในการสร้าง Application บน Ruby Sketchup แต่สำหรับคนเขียนโปรแกรมเมื่อเทียบกับ C# แล้ว ก็ถือว่า ยัง ยากอยู่มาก ในปัจจุบัน โปรแกรม ที่เขียนบน Dotnet C# มีจำนวนมาก และ มี Class สำเร็จรูป ดีๆ เช่น ฐานข้อมูล การเชื่อมกับ Office Excel หรือ Internet เป็นต้้น และ มีตัวอย่าง C# เช่นใน Codeproject.com ทำให้การสร้าง Application ซับซ้อนสูง ทำได้ อย่างรวดเร็ว โดยเฉพาะการทำ Dialog หรือ Form C# เขียนง่ายมาก เมืื่อเทียบกับ Ruby หรือ MFC C/C++
สำหรับ Sketchup มี Ruby เป็นภาษาในการพัฒนาโปรแกรมเสริม และเราสามารถใช้ C/C++ ในการพัฒนาเชื่อมต่อ ได้ในบทความก่อนหน้านี้ สำหรับ C# มีสถานะที่ต่างกัน เนื่องจาก C# เป็น Manage Code การที่ C/C++ จะเรียก Manage Code ซึ่งเป็น Subset ที่ใหญ่กว่า จะยากกว่า ที่ Managed Code C# เรียก Unmanaged C/C++ มาก   Microsoft ได้เปิดช่องใว้ทางเดียว คือต้องทำให้ Managed Code C# เป็น COM หรือ Component Object Model อันเป็นระบบเก่าแก่ของ Microsoftในการเชื่อม ระหว่างโปรแกรมด้วยกัน
ถ้าดูจากวิธีที่จะใช้ C# เข้าไปใน Sketchup นั้น จะเป็นไปตาม Diagram นี้

[Ruby] <----- C/C++ ----> [MFC C/C++] <----- COM----->[C# DotNet]


เร่ิมต้น เราสร้าง Project สำหรับ C# Class ก่อน โดยเปิด Visual Studio 2008 หรือ 2010
และสร้าง Class ตามตัวอย่าง จะเห็นได้ว่า มี Interface เป็นการตั้ง Type สำหรับการติดต่อ กับโปรแกรม
อื่น ตัวอย่างนี้ มี 2  Interface เป็นตัวอย่าง คำนวน บวกค่า และ ตัวอย่างในการแสดง Dialog


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace MathLib
{
    public interface IAddClass
    {
        int Add(int a, int b);
    }
    public class CAddClass : IAddClass
    {
        public int Add(int a, int b)
        {
            return a + b;
        }
       

        public interface IForm1
        {
            int aForm();
        }

        public class CiForm1 : IForm1
        {

            public int aForm()
            {
               
                if (MessageBox.Show("HELLO") == DialogResult.OK)
                {
                    return 1;
                }
                return 0;
            }

        }
    }
}


ก่อนที่จะ Compile ให้สร้าง Stong Name เพื่อให้โปรแกรม Dll ที่ Compile นี้ เป็น Unique
สำหรับโปรแกรมอื่น ไปที่ Visual Studio ->Utitliy->Command Prompt

sn -k myClass.SNK 

ทำการ Copy  SNK นี้ ไปที่ โครงการที่กำลังทำอยู่ จากนั้น Add เข้าไปใน Project 
และ สำหรับการ Build   การ Compile ให้ตั้งค่าที่ Post Build  ใน Build Event

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\regAsm.exe <ชื่อโปรแกรม>.dll /tlb:MathLib.tlb /codebase



จะสร้าง tlb สำหรับให้ C/C++ รู้จัก
สำหรับ ใน โครงการ ให้แก้ AssemblyInfo.cs


[assembly: ComVisible(true)]
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("myClass.SNK")]

จากนั้น ให้ ทำการ Compile โปรแกรม จะได้ Dll พร้อมกับ Tlb สำหร้บ ทำการ Include ใน C/C++ ต่อไป เป็นอันสิ้นสุดการทำ COM ให้ C# ชุดนี้






วันพุธที่ 30 พฤษภาคม พ.ศ. 2555

อ่านค่าตัวแปรจาก Dynamic Block ใน Autocad ด้วยC#

Autocad ตั้งแต่ 2007 เป็นต้นมาการใช้ Dynamic Block เป็นเรื่องปรกติและมีประโยชน์มาก
ในการเปลี่ยนค่า และ การแสดงผล ตามค่าที่ต้องการ เช่นหน้าต่าง ประตู
แต่เดิม ในการวางหน้าต่าง ประตู จะใช้ Block ตามชื่อของ หน้าต่าง เช่น หน้าต่าง 70cm ก็จะใช้
Block  WIN70 ก็จะรู้ว่ามีการวาง หน้าต่าง 70 cm กี่บาน จากการนับ Block แต่ตอนนี้ จะใช้ Block
เดียวที่เป็น Dynamic block และปรับค่าความกว้างของBlock แทน เมื่อนับ Block จะได้ Block เดียวกัน
หมด ไม่ต่างกัน จึงมี โจทย์ ว่าต้องการอ่านค่า ของ Dynamic Block ได้อย่างไร
ใน C# จะต้องใช้ Class DynamicBlockReferencePropertyCollection จัดเก็บเป็น Array ของ ตัวแปร Parameter ที่อยู่ใน Dynamic Block ตามโปรแกรมตัวอย่างนี้ จะเป็นการอ่าน ชื่อค่าแปร และ ค่าตัวแปร ออกมาใน Array ทั้ง 2  คือ paramName และ paraOut (ค่า) โดย Block ที่ส่งเข้าไปคือ br เมื่อเอา paraOut ไปใช้อย่าลืม .ToString() เพื่อเปลี่ยนเป็นตัวหนังสือก่อน







     public static int getDynBlockProperties(ref ArrayList paraName,ref ArrayList paraOut, BlockReference br)
        {
            // Only continue is we have a valid dynamic block
            int count = 0;
            if (br != null && br.IsDynamicBlock)
            {
                // Get the dynamic block's property collection
                DynamicBlockReferencePropertyCollection pc =
                  br.DynamicBlockReferencePropertyCollection;
                // Loop through, getting the info for each property
                foreach (DynamicBlockReferenceProperty prop in pc)
                {
                    // Start with the property name, type and description
                    count++;
                    paraName.Add(prop.PropertyName);
                    paraOut.Add(prop.Value);
                 
                }
            }
            return count;
        }

วันอาทิตย์ที่ 20 พฤษภาคม พ.ศ. 2555

ขึ้นรูปสี่เหลี่ยมใน Sketchup ด้วย Ruby C

เขียนโปรแกรมบน C/C++ กับ Ruby Sketchup ได้ แล้ว ที่นี้ ก็มาเขียน Object ใน Sketchup กัน จะได้
เริ่มทำ Application บน Sketchup ได้

การ Interface กับ Sketchup ด้วย Ruby โดยปรกติจะผ่าน Class Sketchup ข้อดีของโปรแกรม Ruby คือ 
การคำนวนคำสั่ง ไม่จำเป็นต้อง สร้าง Interface ใหม่ใช้ String ในการติดต่อได้เลย โดยจะทำงาน เหมือน
Command Line ของ Ruby

คำสั่ง rb_eval_string_protect จะเป็นคำสั่งในการติดต่อกับ Ruby ใน Sketchup

bool EvaluateRubyExpression(LPCTSTR expr, VALUE* pResult)
{
    if( pResult ) *pResult = Qnil;
    int state = 0;
    VALUE val = rb_eval_string_protect(CT2A(expr), &state);
    if( 0 == state && pResult )
    {
        *pResult = val;
    }

    return (state == 0);
}

ทีนี้ลองเขียน สีเหลี่ยม ขนาด 100x100 ที่ตำแหน่ง x=0,y=0 ดู

void doRectan()
{
VALUE self,name;

   // make a face
    VALUE p1 = EvaluateRubyExpression(_T("p1 = Geom::Point3d.new(0,0,0)"));
    VALUE p2 = EvaluateRubyExpression(_T("p2 = Geom::Point3d.new(100,0,0)"));
    VALUE p3 = EvaluateRubyExpression(_T("p3 = Geom::Point3d.new(100,100,0)"));
    VALUE p4 = EvaluateRubyExpression(_T("p4 = Geom::Point3d.new(0,100,0)"));

   EvaluateRubyExpression(_T("Sketchup.active_model.entities.add_face(p1,p2,p3,p4)"));
}

ตัวแปร p1 ให้เป็น Value จะเป็นจุด และ คำสั่ง Sketchup.active_mode.entities.add_face(..)
เป็นการสร้าง Face สี่เหลี่ยมจากจุด ใน แบบที่กำลังทำงานอยู่
เพิ่มใน คำสั่งใน init_<โปรแกรม>

rb_define_module_function(g_TI_ExtTest, "rectan", (VALUE *) doRectan,0);

ดูผล

ตอนนี้ก็สามารถให้ภาษา C สร้าง Object ใน Sketchup ได้แล้ว



วันอาทิตย์ที่ 13 พฤษภาคม พ.ศ. 2555

Sketckup Ruby C เรียก MFC Dialog

ในการสร้าง Dialog ใน Sketchup Ruby ปรกติแล้วจะใช้ Html และ Javascript ในการสั่งงาน ซึ่งก็ใช้ง่าย
แต่ปัญหา คือการ Debug จะทำไม่ได้ เพราะ เป็น Web และถ้าต้องการทำงานในลักษณะ Interactive
 Dialog ทำไม่ได้ โดยตรง  การใช้งานในลักษณะ Dialog Box จะง่ายกว่า ใน C++ และ  Window จะมี
Dialog อยู่แล้วคือ MFC , Microsoft Foundation Class ซึ่ง ได้พัฒนา เป็น Dotnet
การใช้งาน MFC จะใช้ใน C++
การใช้ Ruby C extension ใช้ MFC ไม่ซับซ้อน ให้ ทำการ New project ใน Visual Studio
เลือกเป็น MFC DLL


ให้เพิ่ม ไฟล์ที่เป็น C สำหรับ ruby init  เช่น initRb.c
แก้ไข init_<ชื่อไฟล์ Dll> เป็น o_<ชื่อDll>
เหตุผลคือ Sketckup เป็นโปรแกรมที่ UserInterface ไม่ได้ ใช้MFC
Sketckup เขียนเอง ทำงานได้ทั้ง Windows และ Mac  การจะใช้ Dialog ของ Mfc จะต้องจัดการ เรื่องสถานะของ Dialog ให้ Windows รับรู้ จึงต้องไปกำหนด ใน ไฟล์ของ MFC


///// Ruby Headers /////
#include <ruby.h>
 VALUE f_Hello( VALUE self );
 static VALUE g_TI_ExtTest; // module 

void o_rbMfc1( void )
{
   // define Module
    g_TI_ExtTest = rb_define_module( "RBMFC" );
    
    rb_define_const( g_TI_ExtTest, "VERSION", rb_str_new2( "1.0" ) );
    
    rb_define_module_function( g_TI_ExtTest, "hi",(VALUE *)f_Hello, 0 );
}

ใน Code ของ MFC ที่สร้างให้ แทรก Code Init



extern "C" void o_rbMfc1( void );
 __declspec( dllexport ) void Init_rbMfc1( void )
{
   // define Module
AFX_MANAGE_STATE(AfxGetStaticModuleState());
 AfxMessageBox("Hello",MB_OK);
   o_rbMfc1();
}



AFX_MANAGE_STATE จะเป็นตัวควบคุม สถานะของ Dialog

ตัวอย่าง คำสั่งของ MFC ใส่ AfxMessageBox เป็น Alert Dialog ที่จะแสดง Hello เมื่อ เรียก Require ใน Ruby Sketchup

Compiler ตั้งค่าเหมือนใน บทความที่แล้ว โดยให้ Output ไปอยู่ที่ folder plugins ของ Sketchup

Compile แล้ว   ทดลอง require ใน Ruby Console จะแสดงหน้าต่าง hello




การเชื่อมกับ MFC เป็นอัน สำเร็จ สำหรับ การสร้าง Dialog ของ MFC ก็ทำตามมาตราฐาน ของ MFC ทั่วไป หาจาก google หรือ youtube และต้องไม่ลืมว่าก่อนการแสดงผลต้อง ทำ AFX_MANAGE_STATE ก่อน


วันอาทิตย์ที่ 6 พฤษภาคม พ.ศ. 2555

โปรแกรม Autocad ด้วย C# Dotnet

แนะนำมาหลายบทความ ลูกศิษย์ถามว่าแล้ว Autocad ที่ใช้ปัจจุบัน จะเขียนโปรแกรมได้อย่างไร
จริงแล้วที่ไม่แนะนำ เพราะมีบทความที่เป็นภาษาอังกฤษ อยู่ มากแล้ว โดยที่
discussion.autodesk.com ใน เรื่องของ dotnet  หรือ Developer คุณ Kean Walmslay
http://through-the-interface.typepad.com/through_the_interface/

จะแนะนำอย่าง ง่ายสำหรับผู้เริ่มต้น
ขั้นต้น ต้องเลือกก่อนว่าจะเลือก บน  Platform อะไร เช่น Autocad 2008
SDK จะอยู่ใน ObjectARX
 หรือ ถ้าเป็น 2010
และ ทำการ Download SDK ที่

http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=1911627

เลือก Autocad Dotnet Wizard
จะต้องลงโปรแกรม Visual Studio 2010 หรือใหม่กว่า ก่อน แล้วค่อยลง Autocad Dotnet

เมื่อลงโปรแกรมเสร็จแล้ว เมื่อเปิด โปรแกรม Visual Studio จะพบว่ามีทางเลือกใหม่
เลือก  "Autocad Managed C# Project"
และมี Default ชื่อโครงการ CsMgdAcad1 ให้เปลี่ยนชื่อเช่น myHello1



ในหน้าต่อไปจะถ้า Register Developer Symbol ถ้าไม่มีก็ใส่ชื่อย่อโครงการไป เช่น MPRJ เป็นต้น
จะสร้าง Commands.cs  แล้วเพิ่ม MessageBox.Show("hello"); ใน Cmd1() โดยจะมี คำสั่งใน Autocad คือ  MPRJCMD1 เปลี่ยนชื่อได้ ตามต้องการ ถ้าต้องการสร้างคำสั่งใหม่ก็ให้   copy คำสั่งนี้ และ Cmd1 วางต่อไปและทำการเปลี่ยนชื่อก็จะได้คำสั่งเพิ่ม


กด Build และ เปิด Autocad เลือก พิมพ์คำสั่ง netload และ เลือกที่ File


c:\Temp\myHello1\myHello1\bin\Debug\myHello1.dll

พิมพ์ คำสั่ง MPRJCMD1 จะแสดง hello ขึ้นมา เป็นอันเสร็จสิ้น การเชื่อมโปรแกรม
C# dot.net กับ Autocad สำหรับการเขียนเส้น น่าจะหาจาก Blog อื่นๆได้


เพิ่มเติม การนำ Class C++ มาใช้กับ Sketchup Ruby C Extension

ตามบทความที่แล้ว เราได้ Interface กับ ruby ของ Sketckup ได้แล้ว แต่ C
เป็นภาษาที่เก่ามาก Source  Code ต่างๆที่จะนำมาใช้จะพัฒนาแบบ OOP หรือ Class Object เป็นส่วนมาก
จะนำมาใช้ได้อย่างไร โดยเฉพาะ พวก Class สำเร็จรูปใน Windows
วิธีการ ให้ทำการ Add New File เลือกเป็น CPP เช่น defFunciton.cpp
ทดลองย้าย f_hello จาก sxhelloworld.C มาที่ defFunction.CPP
ต้องใส่

ใส่
include "ruby.h" ที่หัวไฟล์
extern "C" เข้าหน้า โปรแกรม f_hello เพื่อให้ C++ รู้ว่าจะ ต่อกับโปรแกรม ไฟล์ที่เป็น native  C
จะทำงานได้ ตัวอย่างเป็นการนำ String Class มาใช้ และส่งผลกลับที่ THANAPHAN.hi ใน Ruby Sketchup

source ของ defFunction.cpp



#include <ruby.h>
#include "astring.h"

 extern "C"  VALUE f_Hello( VALUE self )
{
char atxt[80]="OK 2";
 AString oktest("test1");
  oktest+=atxt;
 
    return rb_str_new2( (const char*)oktest);
}