ARESのトリニティ戦略、どこがトリニティなんでしょう。
まずはデスクトップCADが、WindowsにもMacにもLinux版もあるというトリニティ。
デスクトップCADと、モバイルCAD(ARES Touch)と、ブラウザとサーバーCAD(ARES Kudo)のトリニティ。
売り切りのスタンドアローンライセンスと、1〜3年間のバージョンアップ権付きのライセンスと、毎月〜毎年払うサブスクリプションもそうかもしれない。
ARESのトリニティ戦略、どこがトリニティなんでしょう。
まずはデスクトップCADが、WindowsにもMacにもLinux版もあるというトリニティ。
デスクトップCADと、モバイルCAD(ARES Touch)と、ブラウザとサーバーCAD(ARES Kudo)のトリニティ。
売り切りのスタンドアローンライセンスと、1〜3年間のバージョンアップ権付きのライセンスと、毎月〜毎年払うサブスクリプションもそうかもしれない。
Qt for Windows - Building from Source-5/windows-building.html
商用ライセンスの Qt を持っています。Qtのインストーラーに目的のバージョンがあります。→ インストーラーからインストールしてください。
オープンライセンスの Qt のインストーラーに目的のバージョンがあります。 → インストーラーからインストールしてください。
※ Visual Studio 2022 でビルドするときは、Visual Studio 2019 の SDK でも大丈夫。
目的のバージョンがインストーラーからインストールできません。→ 商用ライセンスのライセンスファイルを含めてソースコードからビルドします。
目的のバージョンがインストーラーからインストールできません→ オープンソース版としてソースコードからのビルドします。
ARESマッププラグインでGEOマップを挿入するとGEODATAオブジェクトが用意されます。
GEODATAオブジェクトが利用可能なときは、transformToLonLatAlt() や transformFromLonLatAlt() で緯度経度とXYの変換が可能です。
#include "stdafx.h"
#include "FXHeaders.h" // ほとんどのCFxのヘッダが入っている
#include "DbGeoData.h" // GEODATA オブジェクト
//===========================================================
// JDTESTCmd Class
//===========================================================
int JDTESTCmd::Execute(CFxCommandContext* pCmdCtx)
{
CFxDocumentPtr doc = pCmdCtx->GetFxDocument();
CFxUserIO* io = doc->GetFxUserIO();
CFxDatabasePtr db = doc->GetFxDatabase();
CFxString prompt;
OdResult rt;
// 座標系が用意できているか
OdDbObjectId geoid;
if (oddbGetGeoDataObjId(db, geoid) != eOk)
{
io->Write(L"\nNo GEODATA.");
return RTNORM;
}
OdDbGeoDataPtr geodata = geoid.safeOpenObject();
OdGePoint3d p1;
OdGePoint3d p2;
int rc = io->GetPoint(L"\n位置を指定 : ", nullptr, nullptr, &p1);
if (rc == RTNORM)
{
rt = geodata->transformToLonLatAlt(p1, p2);
prompt.format(L"\n(%f,%f,%f) - (%f,%f,%f) ", p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
io->Write(prompt);
OdError e(rt);
io->Write(e.description());
}
rc = io->GetString(false, L"\n経度,緯度を指定 : ", L"", &prompt);
if (rc == RTNORM)
{
rc = io->GetUnitsFormatter()->StringToPoint(p1, prompt);
if (rc == RTNORM)
{
rt = geodata->transformFromLonLatAlt(p1,p2);
prompt.format(L"\n(%f,%f,%f) - (%f,%f,%f)", p1.x, p1.y, p1.z, p2.x, p2.y, p2.z);
io->Write(prompt);
OdError e(rt);
io->Write(e.description());
}
}
return RTNORM;
}
transformFromLonLatAlt() の戻り値 XYZ の Z がおかしいとき(緯度の値がそのまま入っていることがある)は無視してください。
GEODATA オブジェクトを図面に挿入し、座標変換を利用可能にします。
C++ではGEODATAクラスの座標変換APIが利用できますが、ARESのC#にはGEODATAクラスがありませんでした。しかしPOSITIONMARKER図形クラスはあるのでそれを使って座標変換します。
このプログラムは、POSITIONMARKER 図形を図面に追加して、緯度経度を読み取ったり、緯度経度を設定してXY値を読み取っています。
using Teigha.ApplicationServices;
using Teigha.DatabaseServices;
using Teigha.EditorInput;
using Teigha.Geometry;
using Teigha.Runtime;
using CADException = Teigha.Runtime.Exception;
namespace geodata
{
public class Class1
{
[CommandMethod("TESTCS")]
public void cmdTestCS()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var ed = doc.Editor;
var db = doc.Database;
try
{
var id = db.GeoDataObject;
ed.WriteMessage("\nGEODATA [{0}]", id.Handle.ToString());
}
catch (CADException)
{
ed.WriteMessage("\nNo GEODATA.");
return;
}
var ret = ed.GetPoint("Specify location");
if(ret.Status != PromptStatus.OK )
{
return;
}
var model = db.CurrentSpaceId.GetObject(OpenMode.ForWrite) as BlockTableRecord;
GeoPositionMarker marker = new GeoPositionMarker();
marker.Position = ret.Value;
model.AppendEntity(marker);
Point3d rts = marker.GeoPosition;
ed.WriteMessage("\n{0} -> {1}", ret.Value, rts);
var ret2 = ed.GetString("経度,緯度を入力");
if (ret2.Status == PromptStatus.OK)
{
string text = ret2.StringResult;
int len = text.IndexOf(",");
double lon = System.Convert.ToDouble(text.Substring(0, len));
double lat = System.Convert.ToDouble(text.Substring(len + 1));
Point3d geo = new Point3d(lon,lat,0);
marker.GeoPosition = geo;
rts = marker.Position;
ed.WriteMessage("\n{0} -> {1}", geo, rts);
}
marker.Erase();
}
}
}
緯度経度からXYZに変換したときに、 Z がおかしいとき(緯度の値がそのまま入っていることがある)は無視してください。
: TESTCS
GEODATA [10E]
Specify location: »
(15086629.5460905,4121448.60999969,0) -> (135.525499071023,34.6871623638417,0)
経度,緯度を入力: » 135.5255,34.6871
(135.5255,34.6871,0) -> (15086629.6495038,4121440.16715828,34.6871)
ARESのログファイルは実行したコマンド名しか記録しません。コマンド履歴ウィンドウの内容を取得する方法があれば便利です。
カスタムコマンドを CFx (C++)で作成してみました。
teecommand.h
class TeeCommand : public CFxCommand, CFxOutputDevice
{
public:
virtual const OdString groupName() const { return "TEE_GROUP_NAME"; }
virtual const OdString globalName() const { return "_TEE"; }
virtual const OdString localName() const { return "TEE"; }
virtual int Execute(CFxCommandContext* pCmdCtx);
virtual void CommandOutput(const CFxString& message, const CFxDocument* document);
virtual void SystemOutput(const CFxString& message, const CFxDocument* document);
protected:
TeeCommand(void) {}
~TeeCommand(void) {}
private:
//QString getCoordinates(const OdGePoint3dArray& inp);
QStringList m_output;
int m_prec;
};
teecommand.cpp
void TeeCommand::CommandOutput(const CFxString& message, const CFxDocument* document)
{
m_output.append(message);
}
void TeeCommand::SystemOutput(const CFxString& message, const CFxDocument* document)
{
//m_output.append(message);
}
int TeeCommand::Execute(CFxCommandContext* pCmdCtx)
{
CFxHostAppServicesPtr svc = GetFxSystemServices()->GetHostAppServices();
CFxDocumentPtr doc = pCmdCtx->GetFxDocument();
CFxDatabasePtr db = doc->GetFxDatabase();
CFxUserIO* io = doc->GetFxUserIO();
m_output.clear();
// Specify command.
CFxString command;
CFxString prompt = io->GetPrompt(L"Command name");
int rc = io->GetString(false, prompt, L"", &command);
if (rc != RTNORM)
return RTNORM;
// Specify filename.
QFileInfo fi;
if (db->getDWGTITLED())
{
fi.setFile(QString::fromUtf16(db->getFilename().c_str()));
}
else
{
fi.setFile(
QString::fromUtf16(svc->getMYDOCUMENTSPREFIX().c_str()),
QString::fromUtf16(db->getDWGNAME().c_str())
);
}
CFxString inputname = QString("%1/%2.txt").arg(fi.absolutePath()).arg(fi.completeBaseName());
CFxString filename;
prompt = io->GetPromptString(L"File name", &inputname);
rc = io->GetString(true, prompt, inputname, &filename);
if (rc != RTNORM)
return RTNORM;
// Run command
GetFxSystemServices()->AddOutputDevice(this);
OdResBufPtr cmd = OdResBuf::newRb(OdResBuf::kRtString, command.wide_strU());
GetFxSystemServices()->SendStringToExecute(nullptr, cmd);
GetFxSystemServices()->RemoveOutputDevice(this);
// Write file
QFile fOut(filename);
if (fOut.open(QFile::WriteOnly | QFile::Text))
{
QTextStream s(&fOut);
s.setCodec("shift-jis");
for (int i = 0; i < m_output.size(); ++i)
{
s << m_output.at(i);
}
s.flush();
fOut.close();
}
else
{
io->Write(L"File open error.\n");
}
return RTNORM;
}
ARESのコマンド履歴ウィンドウやコマンドプロンプトウィンドウはQtのウィジェットになっているので text() で内容を取ってくることは可能なのですが、コマンド出力内容が更新されるのは ARES のタイミング次第なので、text() ではうまくいきません。CFx APIに提供されている CFxOutputDevice クラスを利用することで確実にコマンド出力内容を横取りすることができます。
案外覚えやすい、DXFのグループコード。行ってみよう。
基本
0 データ種類{DXF名)
1 文字データ
2 名前(ブロック名など)
3 コメント、追加の文字データ
5 図形ハンドル
6 線種名
7 スタイル名(文字設定)
8 画層名
9 システム変数名
10 座標値
38 高度
39 厚さ
40 実数値(円の半径等)
50 角度値(円弧の開始角等)
60 図形非表示
62 図形色
70 整数値(画層のフラグ等)
90 長整数値
100 クラス名
102 リアクター等の目印
210 押し出し方向
420 フルカラー
430 色名
999 コメント(DXFファイルのみ)
1000 拡張データ 文字データ
1001 学長データID
1002 カツコ
1003 画像名
1005 ハンドル(ソフトリンク)
1010 座標
1040 実数
1070 整数
画層や線種といった各種図形に共通のプロパティは覚えておいて損はない。
図形などデータベースオブジェクトをDXFファイルやリスト形式で表現するほか、図形の選択条件式としても使います。それはLISP以外でも使います。VBAしかり、c++しかり、.NETでも使います。
何このアタオカな処理はって感じですが...
: SHELL
OS コマンドを指定» powershell.exe Invoke-WebRequest -uri "https://cyberjapandata.gsi.go.jp/xyz/std/1/1/0.png" -outfile "c:\temp\std~1~1~0.png"
ARESのSHELLコマンドってのが、コマンドプロンプトへの1行分の処理を行って終了を待って戻ってきます。コマンドプロンプトに powershell.exe とするので PowerShell を1行実行です。ここではInvoke-WebRequest というコマンドレットの実行だけなので引数に処理を全部書いちゃいます。 -Uri ダウンロードするファイル -Outfile 出力先 で行けます。
そこそこ早かったです。
(2024/06/11 追記)
スペースを含むパスを引数にしたいときには、シングルクォートで囲う。
: SHELL
OS コマンドを指定» powershell.exe Invoke-WebRequest -uri ’https://cyberjapandata.gsi.go.jp/xyz/std/1/1/0.png' -outfile 'C:\Users\cadkh\AppData\Local\Temp\ARES Commander Edition_temp\std~0~0~0.png'
盲点であった。
ARESのトリニティ戦略、どこがトリニティなんでしょう。 まずはデスクトップCADが、WindowsにもMacにもLinux版もあるというトリニティ。 デスクトップCADと、モバイルCAD(ARES Touch)と、ブラウザとサーバーCAD(ARES Kudo)のトリニティ。 ...