วันพุธที่ 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);
}

วันศุกร์ที่ 4 พฤษภาคม พ.ศ. 2555

สร้างโปรแกรม ภาษา C บน Google Sketchup


-อ.ธนะพันธ์ อินทรเกสร

ปัญหาของผู้ที่สร้างโปรแกรมบน Sketchup ต้องใช้ ruby ในการเขียนโปรแกรม จะพบว่า การ Debug ยากมาก ใน Project ใหญ่แทบจะหา ไม่เจอเลยว่า โปรแกรม Bug อยู่ที่ใหน เป็นคำถามที่นักศึกษาที่ทำ Project โปรแกรม ด้วย ruby sketchup กลัวกันมาก ผมไปศึกษาเพื่อที่ว่าจะได้ง่ายขึ้น และอีกอย่างเป็นการนำ Library เช่น Database หรือ Graphic หลายอย่างที่พัฒนาบน C มาใช้ ได้โดยไม่ต้อง เขียนใหม่บน ruby
Ruby C Extension
ต้องเข้าใจก่อนว่า ruby ที่อยู่ใน Sketckup ไม่ได้เป็นภาษาเฉพาะของ Sketchup คนเดียว แต่เป็นภาษาที่มีคนใช้ในโปรแกรมหลาย Application เช่น RubyOnRail ใช้ในการทำ Web Server , หรือ Ruby สำหรับ DBMS ในการจัดการฐานข้อมูล เป็นต้น Ruby พัฒนาแกนภาษาโดย
กลุ่ม Opensource

ซึ่งจะพัฒนาเรื่องภาษาเป็นหลัก สำหรับการต่อเชื่อมเข้ากับ Application ต่างๆ จะเป็นเรื่องของโปรแกรมแต่ละคนไปทำกันเอง สำหรับ Sketckup จะใช้ โปรแกรม Ruby Version 1.8.6 เป็น core Language เหมือนกับทุกภาษา แก่นของภาษา ruby พัฒนาบนภาษา C ดังนั้น ถ้าเขียน Application บนภาษา C ก็จะต่อกับ Ruby ได้
การต่อเชื่อมกับ ruby ใน Sketckup ใช้วิธีเดียวกับ การต่อกับ RubyOnRail โดยการสร้างเป็น .so สำหรับบน MAC(OSX) และ .dll สำหรับ Windows และนำเข้าใช้คำสั่ง require ‘ชื่อโปรแกรม’
มีบทความที่น่าจะช่วยได้มาก

และสำหรับ Sketckup

ลุยกันเลยดีกว่า
แล้วจะเริ่มเขียนโปรแกรมอย่างไร เลือก Windows จะสะดวกกว่า เพราะใช้ Visual Studio 2010 ในการพัฒนา
ให้ไป Download Visual Studio 2010 มาจาก www.microsoft.com ใช้ Standard C/C++ ก็พอเพราะฟรี
ต่อไป ต้องไป Download Ruby มากก่อน เลือก Version 1.8.6
และทำการ แตกโปรแกรมลงใน c:\ruby
ทีนี้ต้องใช้ Dos หรือ cmd ผู้ที่ไม่คุ้นเคย จะลำบากพอสมควร แต่ใช้ไม่กีคำสั่ง
เข้าไปที่  path ที่กำหนดเช่น
cd \ruby\ruby-rhg\win32
และเรียกคำสั่ง
configure.bat
และเรียก nmake ต่อ โปรแกรมจะ  compile ruby ให้



ที่สำคัญโปรแกรมจะสร้าง msvcrt-ruby18.lib ที่จะเป็นตัวเชื่อมกับ ruby sketckup ซึ่งต้องตรง version กับใน Sketckup

สร้างโปรแกรมตัวอย่าง
เปิด ​Visual Studio เลือกสร้าง New project เป็น win32 project และเลือกเป็น Empty ในชื่อ sx_hello คือไม่มี Source จากนั้น ให้ Add New Item เป็น C source ชื่อ sxhelloworld.c และ Def ในชื่อ sx_hello.def
ตั้งค่า ใน Project property
General->Configuration Type
Dynamic Library (.dll)
C/C++->Additional Include Directories
"C:\ruby\ruby-rhg";"C:\ruby\ruby-rhg\win32"
C/C++->Command Line
-MD -Ot -Ox -W4
Linker->Output
C:/Program Files/Google/Google SketchUp 8/Plugins/sx_hello.dll
Linker->Additional Dependencies
msvcrt-ruby18.lib
เลือก Output ไปที Plugins ของ google จะ ใช้ Require ได้

Source ของ sxhelloworld.c
///// Ruby Headers /////

#include <ruby.h>


///// Global References ////

static VALUE g_TI_ExtTest; // module


///// Ruby Extension Methods /////

static VALUE f_Hello( VALUE self )
{
    return rb_str_new2( "Hello SketchUp Work!!" );
}


///// Initializer /////

__declspec( dllexport ) void Init_sx_hello( void )
{
   // define Module
    g_TI_ExtTest = rb_define_module( "THANAPHAN" );
   
    // Constants
    // > THANAPHAN::VERSION
    rb_define_const( g_TI_ExtTest, "VERSION", rb_str_new2( "1.0" ) );
   
    // Methods
    // > THANAPHAN.hi
    rb_define_module_function( g_TI_ExtTest, "hi", (VALUE*)f_Hello, 0 );
}

และใน sx_hello.def
LIBRARY     "sx_hello"
EXPORTS
Init_sx_hello


ทั้งใน Source C และ def ต้อง  Export ในชื่อ Init_ชื่อไฟล์ ไม่นั้นจะ ใช้ ruby->require ไม่ได้
ทำการ compile ใน Visual studio  ต้องจบด้วย 1 succeeded จึงจะได้ โปรแกรม
..\..\sxhelloworld.c(32) : warning C4024: 'rb_define_module_function' : different types for formal and actual parameter 3
Linking...
External build tool process set to low priority...
   Creating library C:/Program Files/Google/Google SketchUp 8/Plugins/sx_hello.lib and object C:/Program Files/Google/Google SketchUp 8/Plugins/sx_hello.exp
Embedding manifest...
External build tool process set to low priority...
External build tool process set to low priority...
Build log was saved at "file://c:\ruby\hello\sx_hello\sx_hello\Debug\BuildLog.htm"
sx_hello - 0 error(s), 8 warning(s)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========



ทดลองใน Sketchup เปิด Ruby Console พิมพ์ ตัวหนังสือตามสีฟ้า

require "sx_hello"
true
THANAPHAN::VERSION
1.0
THANAPHAN.hi
Hello SketchUp Work!!


เมื่อ Require จะทำการ load sx_hello.dll เข้ามาในโปรแกรม โดย ruby จะตอบกลับเป็น true  THANAPHAN จะเป็นชื่อ Module และประกอบด้วย constant VERSION และ โปรแกรมใต้ Module ชื่อ hi จะตอบกลับด้วย Hello SketchUp Work!! ส่วนต่อของ Ruby Sketchup และ C ทำงานได้แล้ว
เรื่องที่น่าสนใจคือ C++ ได้หรือไม่ ไม่ยาก เพราะ Syntax ไม่ต่างกัน แต่ถ้าเป็น C# ต้องทำ Class Wrapper ก่อน จึงจะ ต่อได้ ถ้ามีเวลาผมจะ ทดลองมาให้อ่านกัน

ในกรณี Debug โปรแกรม ก็ให้กดที่ปุ่ม Start Debugging ใน Visual Studio และเลือก โปรแกรม Sketchup.exe ใน Folder  Sketckup ก็จะทำงาน ได้ เหมือนการ Debug ปรกติ