2015年4月25日 星期六

#ifdef、#elif、defined

 最近因為想把用Open GL的程式放到OS X跑,把Preprocessor #include的部分改為

#ifdef _WIN32
...
#elif __APPLE__
#include
...
#endif

後來感覺#elif部分怪怪,查了一下,發現#ifdef其實是#if defined的方便寫法,而原本的#elif部分並不是檢查有無define,而是做條件判斷。

隨便寫個C++程式測試:

...
#ifdef NOT_DEFINED
...
#elif ALSO_NOT_DEFINED
  std::cout << "print for test" << std::endl;
...

可編譯,不輸出


...
#define DEFINED

...
#elif DEFINE
  std::cout << "print for test" << std::endl;
...

無法編譯,"error: expected value in expression"


...
#define DEFINED_AS_ZERO 0

...
#elif DEFINED_AS_ZERO
  std::cout << "print for test" << std::endl;
...

可編譯,不輸出


...
#define DEFINED_AS_ONE 1

...
#elif DEFINED_AS_ONE
  std::cout << "print for test" << std::endl;
...

可編譯,有輸出


改用#elif defined,皆可編譯,除ALSO_NOT_DEFINED外皆有輸出


白目想說cout __APPLE__看看,輸出1,無怪乎原本用#elif也能順利include。但#elif define(__APPLE__)感覺較良好,還是改吧。

2015年4月19日 星期日

於MBPR安裝Qwt

安裝

1. 自SourgeForge下載qwt-6.1.2.tar.bz2

brew有Qwt, 但測試安裝好像是綁Qt4

2. tar jxvf qwt-6.1.2.tar.bz2解壓縮檔案

3. (於qwt資料夾)qmake

4. make

5. make install

在Window裝差不多, 就抓的壓縮檔不同和用的compiler, compile指令不同

使用

1. 在要用Qwt的專案.pro檔加上

include (/usr/local/qwt-6.1.2/features/qwt.prf)

程式到這邊qmake, 編譯都沒問題, 但執行時會出現

dyld: dyld: Library not loaded: qwt.framework/Versions/6/qwt
Reference from: (你的檔案路徑)
Reason: image not found
程式未預期終止。

google到解決方法

2. 點Qt Creator左邊"專案", "建置並執行"分頁上方Clang 64bit下建置右邊的"執行", 進"執行設定", 在下面"Run Environment", 點"詳情", 點"新增", 加入變數"DYLD_FRAMEWORK_PATH", 值"/usr/local/qwt-6.1.2/lib"

值和解決方法不同的原因是我qwt lib沒裝在/usr/local/lib, 看大陸人部落格才想起來

3. 執行ok, 收工

這只是透過Qt Creator執行ok就是了, 之後大概要用前面解決方法 b

2015年4月17日 星期五

於MBPR安裝Qt5與Qt Creator - 使用Homebrew

主要參考此網頁, 安裝成功之作業系統為OS X 10.10.3

1. 安裝Homebrew

  • 開啟terminal (以Spotlight搜尋terminal.app)
  • 官網之script(ruby -e "...)貼至terminal執行
  • 按指示完成安裝, 會順便灌好xcode, xcode command line tools, git ...

2. (於terminal) brew update

取得最新版的Homebrew, 我不確定剛下載好是不是需要update.., 但就update吧

3. brew install qt5

經過漫長的下載, 編譯後將Qt安裝在/usr/local/opt/qt5

4. brew linkapps

通過此步驟才能在應用程式找到Assistant, Designer, Linguist.. 雖然說有了Creator我從沒開過Assistant, Designer, 但Spotlight不知為何連不到Designer, Assistant, 還是link一下好

以下說明Creator安裝方法

5. brew install caskroom/cask/qt-creator

正常好像會先brew install caskroom/cask/brew-cask把cask裝好, 但上述步驟應可直接裝好cask, 再裝Qt Creator

再來要於Qt Creator設定使用的Qt版本(qmake位置)及編譯器

6. 開啟Qt Creator(用Spotlight), 選螢幕上方的"工具"-"外部"-"Configure", 開啟喜好設定視窗

7. 點左邊的"建置並執行", 點上方"Qt Versions"分頁, 點右方"新增"

準備連結qmake

8. 從上面的combo box(下拉式表單)選Macintosh HD

qmake在/usr/local/opt/qt5/bin , 但因usr是隱藏資料夾, 無法點選

9. 按鍵盤之 "Command" + "Shift" + "."

跑出usr等一堆隱藏資料夾

10. 打開/usr/local/opt/qt5/bin/qmake

有了qmake產生makefile檔, 再來就是設定使用的Compiler

11. 點上方"Kits"分頁, 點右方"新增", 下方"Compiler"combo box選"Clang (x86 64bit in /usr/bin)", "Qt版本"選"Qt 5.4.1 (5.4.1)"

至此大功告成, 趕快新增Qt Widgets Application測試. 體驗在Windows和Linux垂涎已久的Macintosh Style


可能有時候還是想在terminal執行qmake, 以下說明PATH變數設定方法

1. vim ~/.bash-profile

不會用vim就用別的文字編輯器吧

2. 加上 export PATH="/usr/local/bin:$PATH" , 儲存檔案

3. 重新開啟terminal, echo $PATH確定有/usr/local/opt/qt5/bin

現在已可在terminal run qmake, 可qmake --version看qt版本

2015年4月15日 星期三

以GTAV操作手法於FlightGear飛Cessna 172P - XBOX360搖桿XML檔設定

GTAV PS4控制器按鍵對應

  • 左操作桿-左右: 副翼(Aileron),操作桿向右,飛機右滾轉
  • 左操作桿-上下: 升降舵(Elevator),操作桿向下、升降舵向下
  • L1: 方向舵(Rudder)左擺
  • R2: 方向舵右擺
  • L2: 熄火/減速
  • R2: 發動/加速
  • 右操作桿-左右: heading(or yaw) 視向(view direction),操作桿向右→往右看
  • 右操作桿-上下: pitch 視向,操作桿向下→往下看
  • 左操作桿-按下: 收/放 起落架
  • 右操作桿-按下: 按下-視向轉正後方;放開-視向轉回正前方
  • 觸控版: 改變視角
  • OPTIONS按鈕: 暫停

FlightGear控制器操作設定方法

FlightGear內的搖桿設定GUI功能有限,為達目標需編輯xml檔。

指定連結到特定xml檔

首先,編輯/FlightGear/data/joysticks.xml如下(參考網頁)
<PropertyList>
  <js n="0" include="Input/Joysticks/custom.xml"/>
</PropertyList>
如此,可強制第一支控制器js n="0"(基本上也只會插一個)以/FlightGear/data/Input/Joysticks/custom.xml對應操作按鍵。

編輯joystick xml檔

基本編輯方法建議參考此教學與/data/Docs/readme Command章節。以下僅就如何於各軸(axis)、按鈕(button)實現GTAV操作對應進行說明。

左操作桿-左右

<axis n="0">
  <binding>
property-scale command將property aileron之value設為axis值
    <command type="string">property-scale</command>
    <property type="string">/controls/flight/aileron</property>
  </binding>
</axis>

左操作桿-上下

<axis n="1">
  <binding>
    <command type="string">property-scale</command>
    <property type="string">/controls/flight/elevator</property>
因左操作桿向下為正,而elevator向上為正,故設factor為-1以反轉
    <factor type="double">-1</factor>
  </binding>
</axis>

L1-R1

XBOX 360搖桿之L1-R1不是類比,不能直接對應成L1-R1按多少→Rudder擺多少。
因此,設定成按下R1→Rudder持續向右擺,放開→回歸原點;按下L1→Rudder持續向左擺,方開→回歸原點。
L1
<button n="4">
  <binding>
property-interpolate command以設定之rate變動property rudder至value
    <command type="string">property-interpolate</command>
    <property type="string">/controls/flight/rudder</property>
Rudder左擺極值為-1
    <value type="double">-1</value>
設定rate,即每秒變動量
    <rate type="double">0.5</rate>
  </binding>
mod-up表放開按鈕
  <mod-up>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
放開L1 Rudder回中心,而中心值為0
      <value type="double">0</value>
      <rate type="double">0.5</rate>
    </binding>
  </mod-up>
</button>
R1
<button n="5">
  <binding>
    <command type="string">property-interpolate</command>
    <property type="string">/controls/flight/rudder</property>
Rudder右擺極值為1
    <value type="double">1</value>
    <rate type="double">0.5</rate>
  </binding>
  <mod-up>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">0</value>
      <rate type="double">0.5</rate>
    </binding>
  </mod-up>
</button>

L2-R2

這個最複雜,因為R2同時要包含油門控制+引擎發動,L2要同時包含煞車+引擎熄火,使用nasal script處理
<axis n="2">
  <binding>
    <command type="string">nasal</command>
    <script type="string">
於script中取得axis值
      var axisValue = cmdarg().getNode("setting").getValue(); 

若引擎未啟動、且R2按到接近底(至底axis值為-1),將starter switch設為1,啟動引擎
      if(getprop("/engines/engine/running") != 1
    and -0.9 > axisValue){
  setprop("/controls/switches/starter", 1);

若magnetos未設為3,設為3
  if(getprop("/controls/engines/engine/magnetos") != 3){ <!-- magnetos setting -->
    setprop("/controls/engines/engine/magnetos", 3);
  }
      }
若引擎已啟動,將starter switch設回0
      else{
 setprop("/controls/switches/starter", 0); 
      }

      <!-- axisValue 0~-1, R2, throttle -->
若axis值小於0,即按R2(0~-1),設定油門(0~1)為axis反轉值
      if(0 >= axisValue){
  setprop("/controls/engines/engine/throttle", -axisValue);
      } 

      <!-- axisValue 0~1, L2, brake -->
若axis值大於0,即按L2(0~1),設定左右煞車(0~1)為axis值
      if(axisValue >= 0){ # L2 is positive (0 ~ 1)
 setprop("/controls/gear/brake-left", axisValue);
 setprop("/controls/gear/brake-right", axisValue);
      } 

若axis值大於0.8,即L2按接近底,將magnetos設為0,引擎熄火
      if(axisValue > 0.8 and getprop("/controls/engines/engine/magnetos") != 0){
 setprop("/controls/engines/engine/magnetos", 0)
      }
    </script>
  </binding>
</axis>

右操作桿-左右

<axis n="4">
axis值約小於-0.9,即右操作桿左擺至接近極限時為low。
  <low> <!-- left --> <!-- axis value < -0.9 -->
動作需重複,即右操作桿左擺時持續減小pitch數值
    <repeatable type="string">true</repeatable>
    <binding>
property-adjust command用以將property數值加上step值
      <command type="string">property-adjust</command>
      <property type="string">/sim/current-view/goal-heading-offset-deg</property>
      <step type="double">-1</step>
    </binding>
  </low>
axis值約大於0.9,即右操作桿右擺至接近極限時為high。
  <high> <!-- right --> <!-- axis value > 0.9 -->
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">property-adjust</command>
      <property type="string">/sim/current-view/goal-heading-offset-deg</property>
      <step type="double">1</step>
    </binding>
  </high>
</axis>

右操作桿-上下

<axis n="3">
axis上擺至接近極限為low
  <low>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">property-adjust</command>
      <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
      <step type="double">-1</step>
    </binding>
  </low>
axis上擺至接近極限為high
  <high>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">property-adjust</command>
      <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
      <step type="double">1</step>
    </binding>
  </high>
</axis>

左操作桿-按下

Cessna 172起落架不能收,跳過

右操作桿-按下

按下看正後方,放開跳回正前方。
<button n="9">
設heading為180度 (正後方)
  <binding>
    <command type="string">property-assign</command>
    <property type="string">/sim/current-view/goal-heading-offset-deg</property>
    <value type="double">180</value>
  </binding>
設pitch為0度
  <binding>
    <command type="string">property-assign</command>
    <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
    <value type="double">0</value>
  </binding>
放開
    <mod-up>
設heading為0度 (正前方)
      <binding>
 <command type="string">property-assign</command>
 <property type="string">/sim/current-view/goal-heading-offset-deg</property>
 <value type="double">0</value>
      </binding>
設pitch為0度
      <binding>
 <command type="string">property-assign</command>
 <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
 <value type="double">0</value>
      </binding>
    </mod-up>
</button>

觸控板

用BACK按鈕代替,利用property-cycle command使property於設定之value循環
<button n="6">
  <binding>
    <command type="string">property-cycle</command>
    <property type="string">/sim/current-view/view-number</property>
cockpit view
    <value>0</value>
model view
    <value>7</value>
chase without yaw view
    <value>5</value>
  </binding>
</button>

OPTIONS按鈕

用START按扭代替,直接pause command就好,easy。
<button n="7"> # START button
  <desc type="string">pause</desc>
  <repeatable type="string">false</repeatable>
  <binding>
    <command type="string">pause</command>
  </binding>
</button>

dead-band

前面說明省略dead-band部分。FlightGear之dead-band 結果以下程式碼說明 (可看joystick文件?)
README.Joystick.html,User Guid to FGInput - Joystick And Keyboard Binding For FlightGear
實際dead-band效果如下函式 (1 >= input >= -1, 1 > deadBand > 0 )

double doDeadBand(double input, double deadBand)
{
  if(input >= deadBand){
    return (input - deadBand) / (1 - deadBand);
  }

  if(input > -deadBand){
    return 0.0;
  }

  return -(abs(input) - deadBand) / (1 - deadBand);
}

完整檔案

<?xml version="1.0"?>

<!-- 
  add 

  <PropertyList>
    <js n="0" include="Input/Joysticks/GTA V like joystick setting for XBOX 360 Controller.xml"/>
  </PropertyList> 

  in FlightGear/data/joysticks.xml

  put this file in FlightGear/data/Input/Joysticks
-->

<PropertyList>
  <name type="string">GTA V like joystick setting for XBOX 360 Controller</name>

  <axis n="0">
    <name type="string">left stick left-right (right positive)</name>
    <desc type="string">adjust aileron</desc>
    <dead-band type="double">0.2</dead-band> <!-- dead-band tag must precede binding tag -->
    <!-- if (input < abs(dead-band)) output = 0 -->
    <!-- if (input > dead-band) output = (output - dead-band) / (1 - dead-band) -->
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/aileron</property>
    </binding>
  </axis>

  <axis n="1">
    <name type="string">left stick up-down (down positive)</name>
    <desc type="string">adjust elevator</desc> 
    <dead-band type="double">0.2</dead-band>
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/elevator</property>
      <factor type="double">-1</factor> <!-- down positive, thus inverse -->
    </binding>
  </axis>

  <axis n="2">
    <name type="string">R2-L2 (L2 positive)</name>
    <desc type="string">start stop engine, adjust throttle, brake</desc>
    <dead-band type="double">0.1</dead-band>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        var axisValue = cmdarg().getNode("setting").getValue(); 
        <!-- the value of /input/joysticks/js/axis[2]/binding/setting -->

        <!-- engine start stop control -->
        if(getprop("/engines/engine/running") != 1 <!-- engine not running -->
             and -0.9 > axisValue){ <!-- R2 pushed near end -->
           setprop("/controls/switches/starter", 1);

           if(getprop("/controls/engines/engine/magnetos") != 3){ <!-- magnetos setting -->
             setprop("/controls/engines/engine/magnetos", 3);
           }
        }
        else{ <!-- engine running -->
          setprop("/controls/switches/starter", 0); 
        }

        <!-- axisValue 0~-1, R2, throttle -->
        if(0 >= axisValue){
           setprop("/controls/engines/engine/throttle", -axisValue);
        } 

        <!-- axisValue 0~1, L2, brake -->
        if(axisValue >= 0){ # L2 is positive (0 ~ 1)
          setprop("/controls/gear/brake-left", axisValue);
          setprop("/controls/gear/brake-right", axisValue);
        } 

        <!-- close engine -->
        if(axisValue > 0.8 and getprop("/controls/engines/engine/magnetos") != 0){
          setprop("/controls/engines/engine/magnetos", 0)
        }
      </script>
    </binding>
  </axis>

  <axis n="3">
    <name type="string">right stick up-down (down positive)</name>
    <desc type="string">adjust view direction pitch</desc>
    <low> <!-- up --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- down --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
<!-- add 

  <PropertyList>
    <js n="0" include="Input/Joysticks/GTA V like joystick setting for XBOX 360 Controller.xml"/>
  </PropertyList> 

  in FlightGear/data/joysticks.xml

  put this file in FlightGear/data/Input/Joysticks
-->

<?xml version="1.0"?>

<PropertyList>
  <name type="string">GTA V like joystick setting for XBOX 360 Controller</name>

  <axis n="0">
    <name type="string">left stick left-right (right positive)</name>
    <desc type="string">adjust aileron</desc>
    <dead-band type="double">0.2</dead-band> <!-- dead-band tag must precede binding tag -->
    <!-- if (input < abs(dead-band)) output = 0 -->
    <!-- if (input > dead-band) output = (output - dead-band) / (1 - dead-band) -->
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/aileron</property>
    </binding>
  </axis>

  <axis n="1">
    <name type="string">left stick up-down (down positive)</name>
    <desc type="string">adjust elevator</desc> 
    <dead-band type="double">0.2</dead-band>
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/elevator</property>
      <factor type="double">-1</factor> <!-- down positive, thus inverse -->
    </binding>
  </axis>

  <axis n="2">
    <name type="string">R2-L2 (L2 positive)</name>
    <desc type="string">start stop engine, adjust throttle, brake</desc>
    <dead-band type="double">0.1</dead-band>
    <binding>
<!-- add 

  <PropertyList>
    <js n="0" include="Input/Joysticks/GTA V like joystick setting for XBOX 360 Controller.xml"/>
  </PropertyList> 

  in FlightGear/data/joysticks.xml

  put this file in FlightGear/data/Input/Joysticks
-->

<?xml version="1.0"?>

<PropertyList>
  <name type="string">GTA V like joystick setting for XBOX 360 Controller</name>

  <axis n="0">
    <name type="string">left stick left-right (right positive)</name>
    <desc type="string">adjust aileron</desc>
    <dead-band type="double">0.2</dead-band> <!-- dead-band tag must precede binding tag -->
    <!-- if (input < abs(dead-band)) output = 0 -->
    <!-- if (input > dead-band) output = (output - dead-band) / (1 - dead-band) -->
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/aileron</property>
    </binding>
  </axis>

  <axis n="1">
    <name type="string">left stick up-down (down positive)</name>
    <desc type="string">adjust elevator</desc> 
    <dead-band type="double">0.2</dead-band>
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/elevator</property>
      <factor type="double">-1</factor> <!-- down positive, thus inverse -->
    </binding>
  </axis>

  <axis n="2">
    <name type="string">R2-L2 (L2 positive)</name>
    <desc type="string">start stop engine, adjust throttle, brake</desc>
    <dead-band type="double">0.1</dead-band>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        var axisValue = cmdarg().getNode("setting").getValue(); 
        <!-- the value of /input/joysticks/js/axis[2]/binding/setting -->

        <!-- engine start stop control -->
        if(getprop("/engines/engine/running") != 1 <!-- engine not running -->
             and -0.9 > axisValue){ <!-- R2 pushed near end -->
           setprop("/controls/switches/starter", 1);

           if(getprop("/controls/engines/engine/magnetos") != 3){ <!-- magnetos setting -->
             setprop("/controls/engines/engine/magnetos", 3);
           }
        }
        else{ <!-- engine running -->
          setprop("/controls/switches/starter", 0); 
        }

        <!-- axisValue 0~-1, R2, throttle -->
        if(0 >= axisValue){
           setprop("/controls/engines/engine/throttle", -axisValue);
        } 

        <!-- axisValue 0~1, L2, brake -->
        if(axisValue >= 0){ # L2 is positive (0 ~ 1)
          setprop("/controls/gear/brake-left", axisValue);
          setprop("/controls/gear/brake-right", axisValue);
        } 

        <!-- close engine -->
        if(axisValue > 0.8 and getprop("/controls/engines/engine/magnetos") != 0){
          setprop("/controls/engines/engine/magnetos", 0)
        }
      </script>
    </binding>
  </axis>

  <axis n="3">
    <name type="string">right stick up-down (down positive)</name>
    <desc type="string">adjust view direction pitch</desc>
    <low> <!-- up --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- down --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <axis n="4">
    <name type="string">right stick left-right (right positive)</name>
    <desc type="string">adjust view direction heading (yaw)</desc>
    <low> <!-- left --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- right --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <button n="0">
    <name type="string">A button</name>
    <desc type="string">decrease elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(-1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="1">
    <name type="string">B button</name>
    <desc type="string">increase aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="2">
    <name type="string">X button</name>
    <desc type="string">decrease aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(-1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)  
      </script>
    </binding>
  </button>

  <button n="3">
    <name type="string">Y button</name>
    <desc type="string">increase elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button> 
  
  <button n="4">
    <name type="string">L1 button</name>
    <desc type="string">Rudder Right (Turn Left)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">-1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release L1 button --> 
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="5">
    <name type="string">R2 button</name>
    <desc type="string">Rudder Left (Turn Right)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release R2 button -->
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="6">
    <name type="string">BACK button</name>
    <desc type="string">change view</desc>
    <binding>
      <command type="string">property-cycle</command>
      <property type="string">/sim/current-view/view-number</property>
      <value>0</value> <!-- cockpit view -->
      <value>7</value> <!-- model view -->
      <value>5</value> <!-- chase without yaw view -->
    </binding>
  </button>

  <button n="7">
    <name type="string">START button</name>
    <desc type="string">pause</desc>
    <binding>
      <command type="string">pause</command>
    </binding>
  </button>

  <button n="9">
    <name type="string">right stick button</name>
    <desc type = "string">look back, look forward when released</desc>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        setprop("/sim/current-view/goal-heading-offset-deg", 180);
        setprop("/sim/current-view/goal-pitch-offset-deg", 0);
      </script>
    </binding>
    <mod-up>
      <binding>
        <command type="string">nasal</command>
        <script type="string">
          setprop("/sim/current-view/goal-heading-offset-deg", 0);
          setprop("/sim/current-view/goal-pitch-offset-deg", 0);
        </script>
      </binding>
    </mod-up>
  </button>
</PropertyList>
      <command type="string">nasal</command>
      <script type="string">
        var axisValue = cmdarg().getNode("setting").getValue(); 
        <!-- the value of /input/joysticks/js/axis[2]/binding/setting -->

        <!-- engine start stop control -->
        if(getprop("/engines/engine/running") != 1 <!-- engine not running -->
             and -0.9 > axisValue){ <!-- R2 pushed near end -->
           setprop("/controls/switches/starter", 1);

           if(getprop("/controls/engines/engine/magnetos") != 3){ <!-- magnetos setting -->
             setprop("/controls/engines/engine/magnetos", 3);
           }
        }
        else{ <!-- engine running -->
          setprop("/controls/switches/starter", 0); 
        }

        <!-- axisValue 0~-1, R2, throttle -->
        if(0 >= axisValue){
           setprop("/controls/engines/engine/throttle", -axisValue);
        } 

        <!-- axisValue 0~1, L2, brake -->
        if(axisValue >= 0){ # L2 is positive (0 ~ 1)
          setprop("/controls/gear/brake-left", axisValue);
          setprop("/controls/gear/brake-right", axisValue);
        } 

        <!-- close engine -->
        if(axisValue > 0.8 and getprop("/controls/engines/engine/magnetos") != 0){
          setprop("/controls/engines/engine/magnetos", 0)
        }
      </script>
    </binding>
  </axis>

  <axis n="3">
    <name type="string">right stick up-down (down positive)</name>
    <desc type="string">adjust view direction pitch</desc>
    <low> <!-- up --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- down --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <axis n="4">
    <name type="string">right stick left-right (right positive)</name>
    <desc type="string">adjust view direction heading (yaw)</desc>
    <low> <!-- left --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- right --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>
<!-- add 

  <PropertyList>
    <js n="0" include="Input/Joysticks/GTA V like joystick setting for XBOX 360 Controller.xml"/>
  </PropertyList> 

  in FlightGear/data/joysticks.xml

  put this file in FlightGear/data/Input/Joysticks
-->

<?xml version="1.0"?>

<PropertyList>
  <name type="string">GTA V like joystick setting for XBOX 360 Controller</name>

  <axis n="0">
    <name type="string">left stick left-right (right positive)</name>
    <desc type="string">adjust aileron</desc>
    <dead-band type="double">0.2</dead-band> <!-- dead-band tag must precede binding tag -->
    <!-- if (input < abs(dead-band)) output = 0 -->
    <!-- if (input > dead-band) output = (output - dead-band) / (1 - dead-band) -->
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/aileron</property>
    </binding>
  </axis>

  <axis n="1">
    <name type="string">left stick up-down (down positive)</name>
    <desc type="string">adjust elevator</desc> 
    <dead-band type="double">0.2</dead-band>
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/elevator</property>
      <factor type="double">-1</factor> <!-- down positive, thus inverse -->
    </binding>
  </axis>

  <axis n="2">
    <name type="string">R2-L2 (L2 positive)</name>
    <desc type="string">start stop engine, adjust throttle, brake</desc>
    <dead-band type="double">0.1</dead-band>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        var axisValue = cmdarg().getNode("setting").getValue(); 
        <!-- the value of /input/joysticks/js/axis[2]/binding/setting -->

        <!-- engine start stop control -->
        if(getprop("/engines/engine/running") != 1 <!-- engine not running -->
             and -0.9 > axisValue){ <!-- R2 pushed near end -->
           setprop("/controls/switches/starter", 1);

           if(getprop("/controls/engines/engine/magnetos") != 3){ <!-- magnetos setting -->
             setprop("/controls/engines/engine/magnetos", 3);
           }
        }
        else{ <!-- engine running -->
          setprop("/controls/switches/starter", 0); 
        }

        <!-- axisValue 0~-1, R2, throttle -->
        if(0 >= axisValue){
           setprop("/controls/engines/engine/throttle", -axisValue);
        } 

        <!-- axisValue 0~1, L2, brake -->
        if(axisValue >= 0){ # L2 is positive (0 ~ 1)
          setprop("/controls/gear/brake-left", axisValue);
          setprop("/controls/gear/brake-right", axisValue);
        } 

        <!-- close engine -->
        if(axisValue > 0.8 and getprop("/controls/engines/engine/magnetos") != 0){
          setprop("/controls/engines/engine/magnetos", 0)
        }
      </script>
    </binding>
  </axis>

  <axis n="3">
    <name type="string">right stick up-down (down positive)</name>
    <desc type="string">adjust view direction pitch</desc>
    <low> <!-- up --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- down --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <axis n="4">
    <name type="string">right stick left-right (right positive)</name>
    <desc type="string">adjust view direction heading (yaw)</desc>
    <low> <!-- left --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- right --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <button n="0">
    <name type="string">A button</name>
    <desc type="string">decrease elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(-1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="1">
    <name type="string">B button</name>
    <desc type="string">increase aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="2">
    <name type="string">X button</name>
    <desc type="string">decrease aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(-1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)  
      </script>
    </binding>
  </button>

  <button n="3">
    <name type="string">Y button</name>
    <desc type="string">increase elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button> 
  
  <button n="4">
    <name type="string">L1 button</name>
    <desc type="string">Rudder Right (Turn Left)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">-1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release L1 button --> 
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="5">
    <name type="string">R2 button</name>
    <desc type="string">Rudder Left (Turn Right)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release R2 button -->
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="6">
    <name type="string">BACK button</name>
    <desc type="string">change view</desc>
    <binding>
      <command type="string">property-cycle</command>
      <property type="string">/sim/current-view/view-number</property>
      <value>0</value> <!-- cockpit view -->
      <value>7</value> <!-- model view -->
      <value>5</value> <!-- chase without yaw view -->
    </binding>
  </button>

  <button n="7">
    <name type="string">START button</name>
    <desc type="string">pause</desc>
    <binding>
      <command type="string">pause</command>
    </binding>
  </button>

  <button n="9">
    <name type="string">right stick button</name>
    <desc type = "string">look back, look forward when released</desc>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        setprop("/sim/current-view/goal-heading-offset-deg", 180);
        setprop("/sim/current-view/goal-pitch-offset-deg", 0);
      </script>
    </binding>
    <mod-up>
      <binding>
        <command type="string">nasal</command>
        <script type="string">
          setprop("/sim/current-view/goal-heading-offset-deg", 0);
          setprop("/sim/current-view/goal-pitch-offset-deg", 0);
        </script>
      </binding>
    </mod-up>
  </button>
</PropertyList>

  <button n="0">
    <name type="string">A button</name>
    <desc type="string">decrease elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(-1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="1">
    <name type="string">B button</name>
    <desc type="string">increase aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="2">
    <name type="string">X button</name>
    <desc type="string">decrease aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(-1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)  
      </script>
    </binding>
  </button>

  <button n="3">
    <name type="string">Y button</name>
    <desc type="string">increase elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button> 
  
  <button n="4">
    <name type="string">L1 button</name>
    <desc type="string">Rudder Right (Turn Left)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">-1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release L1 button --> 
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="5">
    <name type="string">R2 button</name>
    <desc type="string">Rudder Left (Turn Right)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release R2 button -->
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="6">
    <name type="string">BACK button</name>
    <desc type="string">change view</desc>
    <binding>
      <command type="string">property-cycle</command>
      <property type="string">/sim/current-view/view-number</property>
      <value>0</value> <!-- cockpit view -->
      <value>7</value> <!-- model view -->
      <value>5</value> <!-- chase without yaw view -->
    </binding>
  </button>

  <button n="7">
    <name type="string">START button</name>
    <desc type="string">pause</desc>
    <binding>
      <command type="string">pause</command>
    </binding>
  </button>

  <button n="9">
    <name type="string">right stick button</name>
    <desc type = "string">look back, look forward when released</desc>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        setprop("/sim/current-view/goal-heading-offset-deg", 180);
        setprop("/sim/current-view/goal-pitch-offset-deg", 0);
      </script>
    </binding>
    <mod-up>
      <binding>
        <command type="string">nasal</command>
        <script type="string">
          setprop("/sim/current-view/goal-heading-offset-deg", 0);
          setprop("/sim/current-view/goal-pitch-offset-deg", 0);
        </script>
      </binding>
    </mod-up>
  </button>
</PropertyList>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <axis n="4">
    <name type="string">right stick left-right (right positive)</name>
    <desc type="string">adjust view direction heading (yaw)</desc>
    <low> <!-- left --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- right --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <button n="4">
    <name type="string">L1 button</name>
    <desc type="string">Rudder Right (Turn Left)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">-1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release L1 button --> 
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="5">
    <name type="string">R2 button</name>
    <desc type="string">Rudder Left (Turn Right)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release R2 button -->
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="6">
    <name type="string">BACK button</name>
    <desc type="string">change view</desc>
    <binding>
      <command type="string">property-cycle</command>
      <property type="string">/sim/current-view/view-number</property>
      <value>0</value> <!-- cockpit view -->
      <value>7</value> <!-- model view -->
      <value>5</value> <!-- chase without yaw view -->
    </binding>
  </button>

  <button n="7">
    <name type="string">START button</name>
    <desc type="string">pause</desc>
    <binding>
      <command type="string">pause</command>
    </binding>
  </button>

  <button n="9">
    <name type="string">right stick button</name>
    <desc type = "string">look back, look forward when released</desc>
    <binding>
      <command type="string">property-assign</command>
      <property type="string">/sim/current-view/goal-heading-offset-deg</property>
      <value type="double">180</value>
    </binding>
    <binding>
      <command type="string">property-assign</command>
      <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
      <value type="double">0</value>
    </binding>
    <mod-up>
      <binding>
 <command type="string">property-assign</command>
 <property type="string">/sim/current-view/goal-heading-offset-deg</property>
 <value type="double">0</value>
      </binding>
      <binding>
 <command type="string">property-assign</command>
 <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
 <value type="double">0</value>
      </binding>
    </mod-up>
  </button>
</PropertyList>

Qwt安裝 - Windows

操作環境

  • 作業系統: Windows 7
  • 現有Qt版本: 5.2.0 MSVC2012 OpenGL 64bit (使用官方"qt-windows-opensource-5.2.0-msvc2012_opengl-x86_64-offline.exe"Package安裝)
  • 安裝之Qwt版本: Qwt-6.1.2

簡易安裝流程

  1. source forge下載qwt壓縮檔(Windows請下載.zip)
  2. 解壓縮檔案
  3. 設定好PATH變數,方可於命令視窗使用qmake
  4. (命令視窗) qmake qwt.pro
  5. (VS2012 x64 Native Tools Command Prompt) nmake
  6. (VS2012 x64 Native Tools Command Prompt) nmake install

安裝完畢,收工,easy解。

說明

其實Qwt的安裝說明講的很清楚,但自己當初也是不會弄。

Qwt doesn't distribute binary packages

When no binary packages are available (f.e. on Windows) Qwt needs to be compiled and installed on the target system.

簡單講,沒有可以double click後就完成安裝的安裝檔。必須要自己compile source code,install。以下照前述簡易安裝流程說明各步驟。

Path設定

直接在命令視窗列(可以在資料夾內按住shift,點擊右鍵,點選此處開啟命令視窗)打qmake會出現

'qmake' 不是內部或外部命令,可執行的程式或批次檔。

這代表Path變數未設定。Windows 7之qmake Path設定方法如下:

  1. 點選"開始",在"電腦"圖示點擊右鍵,點選"內容",跳出"控制台-系統安全性-系統"視窗
  2. 點選左上方之"進階系統設定",跳出"系統內容"視窗,當下分頁為"進階"
  3. 點選下方的"環境變數",跳出"環境變數"視窗
  4. 於下方"系統變數"框,選"Path"變數反白之,點選下方"編輯",跳出"編輯系統變數"視窗
  5. 編輯"變數值",在尾端加入Qt bin資料夾路徑 (我自己的情況,加入";C:\Qt\Qt5.2.0\5.2.0\msvc2012_64_opengl\bin")
  6. 在"編輯系統變數"視窗點選"確定"
  7. 在"環境變數"視窗點選"確定"
  8. 在"系統內容"視窗點選"確定"

qmake

qmake簡單講就是從.pro檔產生Makefile檔。有了Makefile檔才可進行後續compile, linking等動作。

完成qmake之Path設定後,於解壓縮之qwt-6.1.2資料夾開啟命令視窗,輸入

qmake qwt.pro

命令視窗應無產生任何提示,但資料夾內會生成Makefile檔,已可compile

nmake

nmake是MSVC的compile指令(說明連結),一般的命令視窗輸入nmake會跑出

'nmake'不是內部或外部命令、可執行的程式或批次檔。

因此,要使用Visual Studio的Command Prompt。因為我安裝的Qt版本為64bit,因此compile Qwt也要使用64bit的"VS2012 x64 Native Tools Command Promt",開啟方式為

開始→所有程式→Microsoft Visual Studio 2012→Visual Studio Tools→VS2012 x64 Native Tools Command Promt

開啟Command Prompt後,於方才qmake的工作路徑,輸入

nmake

順利的話就開始漫長的compile時程,請耐心等候。(也沒多久,大概1x min)

nmake install

一樣在"VS2012 x64 Native Tools Command Promt",輸入

nmake install

nmake install應該只是把compile好的檔案複製到路徑(C:/qwt-6.1.2/),複製完畢就大功告成。

補充說明

個人覺得直接用command line比開Qt Creator方便多了,故此分享。

錯誤補充說明

我一開始用到"適用於VS2012的開發人員命令提示字元"32bit的,產生error

Qt5OpenGL.lib(Qt5OpenGL.dll): fatal error LNK1112: 模組電腦類型'x64'與目標電腦類型'X86'衝突
NMAKE : fatal error U1077: 'echo' : 傳回碼'0x458'
...(省略)

google後才知道要用"VS2012 x64 Native Tools Command"

此外,若Qwt路徑有中文,似乎也無法順利compile。