2017年1月24日火曜日

バケットの一覧 +VB.net

現在のバケットの一覧を取得

バケットの一覧を取得するにはDataManagementAPIのGET Bucketを使います。前回のプロジェクトを利用して、WebFormでバケットの一覧を取得してみます。

WebFormの追加

WebFormを追加して、下の図のようにサーバーコントロールを配置します。
サンプルのWebForm

サンプルコード


以下はバケットの一覧を取得するサンプルコードです。ポイントは「apiの戻り値のJSONの配列を処理する部分です。レスポンスをNewtonsoft.Json.Linq.JArray型に変換して情報を取り出します。

Public Class WebForm3
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        '**********************************
        '     アクセストークンを取得
        '**********************************
    'この部分は前回の記事を参照してください。

        Dim acToken As String = mdlUtils.GetToken("bucket:read")
        If acToken = "" Then
            Exit Sub
        End If

        '**********************************
        '     バケットを取得
        '**********************************

        'RestSharpでクライアントを作成
        Dim url As String = "https://developer.api.autodesk.com"
        Dim _client As New RestSharp.RestClient(url)

        'RestSharpでリクエストを作成
        Dim authReq As New RestSharp.RestRequest()
        With authReq
            .Resource = "oss/v2/buckets"

            'メソッド
            .Method = RestSharp.Method.GET

            'ヘッダー
            .AddHeader("Authorization", "Bearer " + acToken)

        End With

        '送信
        'POSTする
        Dim result As RestSharp.IRestResponse = _client.Execute(authReq)

        If result.StatusCode = Net.HttpStatusCode.OK Then

            '200OKの場合

            Dim responseString As String = result.Content
            'Newtonsont.JsonのJSON解読メソッドを使うと便利
            'まず以下の構文でオブジェクトを作成します。
            Dim jsonObj As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(responseString)
            '"items"を取得しjArrayオブジェクトとする
            Dim itemArray As Newtonsoft.Json.Linq.JArray = jsonObj("items")
            '配列を走査する
            For Each item As Newtonsoft.Json.Linq.JObject In itemArray
                'バケットキー
                Dim strBucketKey As String = item("bucketKey")
                '作成した日付(ミリセカンド)
                Dim strCreatedDate As String = item("createdDate")
                'ポリシーキー
                Dim strPolicyKey As String = item("policyKey")

                'タイムスタンプから日付へ変換
                Dim intTimeStamp As Int64 = Int64.Parse(strCreatedDate)
                Dim dtCreateDate As DateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(intTimeStamp)

                'リストボックスのアイテムを追加する
                lbxBuckets.Items.Add(New ListItem(strBucketKey + " / 作成日時 : " + dtCreateDate.ToLocalTime.ToString + " / ポリシーキー : " + strPolicyKey, strBucketKey))

            Next
            lblStatus.Text = itemArray.Count.ToString + "個のバケットが見つかりました。"
        Else
            Dim responseString As String = result.Content
            Dim jsonObj As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(responseString)
            lblStatus.Text = "取得に失敗しました。" + vbTab + jsonObj("reason")


        End If
    End Sub
End Class

実行する

実行すると以下のようになります。
現在のバケットの一覧

2017年1月19日木曜日

バケット作成 + VB.net

バケットを作成する

バケットを作成するにはまずbucket:createスコープでアクセストークンを取得し、ポリシーキー(データの保持期間)とバケット名(bucketId)を決めてPOSTで取得するという手順でした。これをvb.netで実装してみます。

アクセストークン取得モジュール

アクセストークンは様々な場面で必要なので、モジュールで関数にしておきます。

プロジェクトにモジュールを追加して「mdlUtils.vb」とします。以下はコードサンプルです。

Imports System.Net


Module mdlUtils

    Public Const CLIENTID As String = "自分のクライアントID"
    Public Const CLIENTSECRET As String = "自分のクライアントシークレット"
    Private ENDPOINT As String = "https://developer.api.autodesk.com"-

    ''' <summary>
    ''' 目的に応じたアクセストークンを取得する
    ''' </summary>
    ''' <param name="scopeString">スコープ</param>
    ''' <returns></returns>
    Public Function GetToken(ByVal scopeString As String) As String

        'RestSharpでクライアントを作成
        Dim _client As New RestSharp.RestClient(ENDPOINT)
        'RestSharpでリクエストを作成
        Dim authReq As New RestSharp.RestRequest()
        With authReq
            .Resource = "authentication/v1/authenticate"

            'メソッド
            .Method = RestSharp.Method.POST

            'ヘッダー
            .AddHeader("Content-Type", "application/x-www-form-urlencoded")

            'ボディ
            .AddParameter("client_id", CLIENTID)
            .AddParameter("client_secret", CLIENTSECRET)
            .AddParameter("grant_type", "client_credentials")

            'スコープ
            .AddParameter("scope", scopeString)
        End With

        'POSTする
        Dim result As RestSharp.IRestResponse = _client.Execute(authReq)

        If result.StatusCode = HttpStatusCode.OK Then

            '結果(json形式の結果が文字列で返ってくる)
            'このjsonは以下の形式となる
            '{
            '  "token_type": "Bearer",
            '  "expires_in": 1799,
            '  "access_token": "Ff387cyQXw1elOT3nldiFIKBqDOs"
            '}
            Dim responseString As String = result.Content
            'ここからaccess_tokenの値だけを取り出す

            '文字列を操作しても可能だが、Newtonsont.JsonのJSON解読メソッドを使うと便利です。
            '使い方はまず以下の構文でオブジェクトを作成します。
            Dim jsonObj As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(responseString)

            'アクセストークンをオブジェクトに引数を与えて取得します
            Dim acToken As String = jsonObj("access_token")

            'Label1の表示を変更
            Return acToken

        Else
            '失敗した場合
            Return ""
        End If
    End Function
End Module

WebFormの追加


WebFormを一つ追加して、下の図のようにリストボックスとテキストボックス、ラベルを追加します。
WebFormにコントロールを追加

ボタンアクションを追加

btnCreateBucketをダブルクリックして、コードを追加すします。RestSharpで送信するデータは今回はJSONです。

Public Class WebForm2
    Inherits System.Web.UI.Page

    Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles btnCreateBucket.Click

        '**********************************
        '     アクセストークンを取得
        '**********************************

        Dim acToken As String = mdlUtils.GetToken("bucket:create")
        If acToken = "" Then
            Exit Sub
        End If

        '**********************************
        '     バケットを作成
        '**********************************


        'RestSharpでクライアントを作成
        Dim url As String = "https://developer.api.autodesk.com"
        Dim _client As New RestSharp.RestClient(url)

        'RestSharpでリクエストを作成
        Dim authReq As New RestSharp.RestRequest()
        With authReq
            .Resource = "oss/v2/buckets"

            'メソッド
            .Method = RestSharp.Method.POST

            'ヘッダー
            .AddHeader("Content-Type", "application/json")
            .AddHeader("Authorization", "Bearer " + acToken)

            'ボディ(JSON形式で送る場合には匿名型を使用します。)
            '{
            '     "bucketKey":"mybucket",
            '     "policyKey":"transient"
            '}
            .AddJsonBody(New With {
                         Key .bucketKey = tbxBucketKey.Text,
                         Key .policyKey = lbxPolicy.SelectedValue
                         })
        End With

        'POSTする
        Dim result As RestSharp.IRestResponse = _client.Execute(authReq)

        If result.StatusCode = Net.HttpStatusCode.OK Then

            '結果(json形式の結果が文字列で返ってくる)
            '{
            '  "bucketKey":"apptestbucket",
            '  "bucketOwner":"RlKfGlAbb7N8VJwLllOvpfonB1Ex52qG",
            '  "createdDate":1463785698600,
            '  "permissions":[
            '    {
            '      "authId":"RlKffonB1Ex52GlAbb7N8VJwLllOvpqG",
            '      "access":"full"
            '    }
            '  ],
            '  "policyKey":"transient"
            '}
            Dim responseString As String = result.Content
            '文字列を操作しても可能だが、Newtonsont.JsonのJSON解読メソッドを使うと便利。
            '使い方はまず以下の構文でオブジェクトを作成します。
            Dim jsonObj As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(responseString)
            'バケットキーを取り出す
            Dim bucketKeyString As String = jsonObj("bucketKey")
            'ステータスに出力
            lblStatus.Text = bucketKeyString + "の作成に成功しました。"

        Else
            'エラーの場合は理由を示すJSONが返ってくる
            '            {
            '  "reason":"Valid field 'bucketKey' must be of the form  [-_.a-z0-9]{3,128}"
            '}
            Dim responseString As String = result.Content
            Dim jsonObj As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(responseString)
            Dim reasonString As String = jsonObj("reason")
            lblStatus.Text = "バケットの作成に失敗しました。理由:" + reasonString

        End If
    End Sub
End Class

RestSharpでJSONを送る

RestSharpでBODYにJSON形式のデータをセットする場合は、赤字で示した部分のように.AddJsonBodyの引数に匿名型のオブジェクトをセットします。

実行してみる


ビルドして実行してみます。
ブラウザで実行
データ保存期間とバケットキーを指定して「バケット作成」を押すと
バケットが作成された
もう一度押すとすでに同じ名前のバケットがあることがわかります。
同じ名前のバケットは作成できない
バケットの名前に大文字のアルファベットを使うと、同じくエラーになります。
文字の制約のエラー


2017年1月15日日曜日

アクセストークン + VB.net

サーバーサイドでアクセストークンを取得する

ここまでで基本的な知識は手に入りました。ここからはASP.NET WebFormを使って、FORGEに取り組んでみます。ビューアのチュートリアルでは、JavaScriptに直接

  • オブジェクトID
  • アクセストークン

を書き込んでいました。また、アクセストークンを取得するには
  • クライアントID
  • クライアントシークレット
が必要です。しかし、クライアントサイドのJavaScriptはブラウザーの開発者ツールを使えば「もろばれ」状態なので、大事な情報をクライアントサイドに置くわけにはいきません。

今回はWebFormを使って、アクセストークンを取得してみます。Webフォームのアクションはサーバーサイドで実行されるので、大事な情報をクライアントサイドに置かなくて済みます。

まずはVisual Studioで新しいWebFormプロジェクトを作成します。

RestSharpを導入する

アクセストークンを取得するにはRESTを使って、交信を行う必要があることがわかりました。VBでこれを実装するのはなかなか骨が折れそうですが、RestSharpを使うことでこの難関を切り抜けることができます。プロジェクトにRestSharpを組み込みます。

(1) [ツール]-[NuGetパッケージマネージャ]-[パッケージマネージャコンソール]
(2) パッケージマネージャコンソールで
  PM> Install-Package RestSharp

WebFormを追加


(1) [プロジェクト]-[新しい項目の追加]
(2) [Webフォーム]を選択して[追加]
(3) 画面左下の[並べて表示]をクリック
(4) ボタンとラベルを追加

ボタンのアクションを追加

(1) 追加したボタンをダブルクリックして、コードを表示する
(2) コードは以下のようになります。

Imports System.Net

Public Class WebForm1
    Inherits System.Web.UI.Page


    Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        'ラベルをクリア
        Label1.Text = ""

        'クライアントIDとクライアントシークレット
        Dim client_id As String = "自分のクライアントIDで置き換え"
        Dim client_secret As String = "自分のクラインとシークレットで置き換え"

        'URL
        Dim strClient As String = "https://developer.api.autodesk.com"

        'RestSharpでクライアントを作成
        Dim _client As New RestSharp.RestClient(strClient)
        'RestSharpでリクエストを作成
        Dim authReq As New RestSharp.RestRequest()
        With authReq
            .Resource = "authentication/v1/authenticate"

            'メソッド
            .Method = RestSharp.Method.POST

            'ヘッダー
            .AddHeader("Content-Type", "application/x-www-form-urlencoded")

            'ボディ
            .AddParameter("client_id", client_id)
            .AddParameter("client_secret", client_secret)
            .AddParameter("grant_type", "client_credentials")

            'スコープはとりあえずdata:read
            .AddParameter("scope", "data:read")
        End With

        'リクエストを送信
        Dim result As RestSharp.IRestResponse = _client.Execute(authReq)

        If result.StatusCode = HttpStatusCode.OK Then

            '結果(json形式の結果が文字列で返ってくる)
            'このjsonは以下の形式となる
            '{
            '  "token_type": "Bearer",
            '  "expires_in": 1799,
            '  "access_token": "Ff387cyQXw1elOT3nldiFIKBqDOs"
            '}
            Dim responseString As String = result.Content
            'ここからaccess_tokenの値だけを取り出す

            '文字列を操作しても可能だが、Newtonsont.Jsonの解読メソッドを使うと便利です。
            '使い方はまず以下の構文でオブジェクトを作成します。
            Dim jsonObj As Object =  Newtonsoft.Json.JsonConvert.DeserializeObject(responseString)

            'アクセストークンをオブジェクトに引数を与えて取得します
            Dim acToken As String = jsonObj("access_token")

            'Label1の表示を変更
            Label1.Text = acToken

        Else
            '失敗した場合
            Label1.Text = "アクセストークンを取得できませんでした。"

        End If

    End Sub
End Class

ポイントはRestSharpのリクエストの作り方と、戻り値のJSONからaccess_tokenの値と取り出す部分です。Newtonsoft.Jsonは規定でASP.netに組み込まれているので、特に参照を操作する必要はありません。

実行してみる


ビルドして実行してみます。最初の画面はこうです。
ボタンを押してみましょう
ボタンを押すと
アクセストークンが取得できた!
アクセストークンが取得できました。
結構少ないコードで、安全にアクセストークンを取得できることがわかりました。

2017年1月6日金曜日

ビューアで表示する(2)~表示ビューの変更

3Dビューが表示されたのは偶然だった?

前回無事ビューアで表示できたので、今回はチュートリアルのStep3を解明してみます。考えてみれば、Revitのデータをアップロードして、2dと3dのビューを表示用に変換するように、命令をしたわけですから、前回のビューアで表示するように指定したビューには複数のビューがあったはずです。にもかかわらず、3Dビューが表示されたのは「単なる偶然」だったのですね。
運よく?表示された3Dビュー
Step3では画面上部に「Nextボタン」を表示して、クリックするごとに表示可能ビューを入れ変えるようにしてみます。

Step3 をフォローする

ボタンをつくる

まずビューアの上にボタンを作成します。これはHTMLファイルの<div>で区切られたビューアの
<div id="MyViewerDiv"></div>
の行の直後に
<button id="MyNextButton" onClick="loadNextModel()">Next!</button>
とボタンタグを加えます。
ボタンのIDはMyNextButtonで、onClickイベントにloadNextModel()関数を指定しています。
次にボタンのスタイルを指定するために、<head>~</head>内の<style>~</style>タグのなかに
#MyNextButton {
        position: absolute;
        top: 5px;
        left: 5px;
        z-index: 1;
        font-size: 40px;
        cursor: pointer;
    }
と付け加えます。従いまして、Visual Studioとしては下の図のようになります。
ボタンのスタイルとタグを追加

onClickイベント関数の追加

ボタンをクリックしたときに処理される関数を記述します。とりあえず
function loadNextModel() {
    console.log('TODO: Load Next Model');
}
を追加するのですが、問題はどこに追加するのか?ということです。HTMLファイルにJavaScriptを記述する場合、<script>~</script>タグの間に記述するので、とりあえず、下のほうの</script>の直上に入れておきます。
</script>の直上にいれる

グローバル変数の追加

すでに<script>タグの直後に var viewer; というグローバル変数が宣言されていますが、これにあと三つのグローバル変数を追加します。

        var lmvDoc;
        var viewables;
        var indexViewable;

したがって、以下の図の位置に入ります。
グローバル変数を追加

ロード成功時の関数(onDocumentLoadSuccess)の変更

既存のonDocumentLoadSuccess()を以下の内容で書き換えます。
function onDocumentLoadSuccess(doc) {

    // docにある2Dおよび3Dの表示可能なビューの配列をグローバル変数viewablesに格納
    viewables = Autodesk.Viewing.Document.getSubItemsWithProperties(doc.getRootItem(), {'type':'geometry'}, true);
  // 表示可能なビューがなければ終了
    if (viewables.length === 0) {
        console.error('Document contains no viewables.');
        return;
    }

    // ビューアを<div id=MyViewerDiv>に作成しグローバル変数viewerに格納
    var viewerDiv = document.getElementById('MyViewerDiv');
    viewer = new Autodesk.Viewing.Private.GuiViewer3D(viewerDiv);
    var errorCode = viewer.start();

    // ビューアの初期化時のエラーを確認する
    if (errorCode) {
        console.error('viewer.start() error - errorCode:' + errorCode);
        return;
    }

    // グローバル変数indexViewableを0に初期化し、グローバル偏すlmvDocにdocを格納.
    indexViewable = 0;
    lmvDoc = doc;

    // loadModel関数を呼び出して、ビューアにモデルをロードする
    loadModel();
}


働きはコメントをつけておきましたが、そもそもなぜonDocumentLoadSuccessに引数(doc)があるのかがわかりませんね。この関数自体は、Document.Load関数の第二引数の「onSuccessCallback」なのですが、これが引数をとるなどという記述は、HELPにはどこにもないですから。

これらの謎は後日調べて報告します。

さて、この関数の最後にあるloadModel()を、onDocumentLoadSuccess関数の後に記入します。
function loadModel() {
    var initialViewable = viewables[indexViewable];
    var svfUrl = lmvDoc.getViewablePath(initialViewable);
    var modelOptions = {
        sharedPropertyDbPath: lmvDoc.getPropertyDbPath()
    };
    viewer.loadModel(svfUrl, modelOptions, onLoadModelSuccess, onLoadModelError);
}

そして最後に、onClickイベント関数 loadModel を次の関数で置き換えます。
function loadNextModel() {

    viewer.tearDown();
    viewer.setUp(viewer.config);

    // インデックスを+1して次のビューをロード。最後まで行ったら0に戻る
    indexViewable = (indexViewable + 1) % viewables.length;
    loadModel();
}

これで実行してみると、まず下の図のように3Dビューが表示されます。
左上のNEXTボタンを押す
が、左上に表示された[Next!]ボタンをクリックすると
2D図面が表示される
2D図面が表示されます。押し続けると次々と図面が表示されて、また最初の3Dビューに戻ります。

さて、関数とAPI Referenceと見比べてみますと、onDocumentLoadSuccess関数のviewerのインスタンスを作成する「Autodesk.Viewing.Private.GuiViewer3D(viewerDiv);」は、リファレンスには見当たりません。代わりに

というnew関数がありますので、この部分を

viewer = new Autodesk.Viewing.Viewer3D(viewerDiv);

と書き換えて実行してみます。実行後は[F5]などで、キャッシュを除去してください。これでも問題なく動くはずです。


What's next?


おお!無事に表示されたぞ。と喜んでいると一番下のWhat's next?の段落に

「ここに紹介されているコードの多くは、物事を稼働させるために必要な定型文です。 ViewingApplicationオブジェクトを使用すると、その一部を簡略化できます。」

とあります。ここにあるのはbioplate(定型文・決まり文句)なので、次のチュートリアルをやってみましょう、と言っております。

さてさて、「ViewingApplication」とはどのようなものなのでしょうか?

でも、ここらでチュートリアルで習ったことを使って、自分でWebアプリケーションを作ってみようではないですか!

2016年12月23日金曜日

ビューアで表示する

変換したデータをFORGEビューアで表示してみます。今まではDHCを使って直接RESTを送受信していましたが、ビューアですからいよいよWebページが必要です。うーむ、これは未知の世界だ。Visual Studioでやるんだから当然.ASP.NETですね。

Visual Studio でFORGEを攻略


(1) Visual Studio を起動し[新しいプロジェクト]を選択
(2) 新しいプロジェクトダイアログボックスで[Web]-[ASP.NET Webアプリケーション]を選択。プロジェクト名は「TryForgeViewer」としてみました。
やっぱ、ASP.NETでしょう
(3) 新しいASP.NETプロジェクトでは、ノーマル?にWeb Formを選びました。Web Formには様々な異論があるようですが、詳細を知らないことをいいことにこれを選択します。だって、デスクトッププログラマとしては慣れたイベントドリブン方式が便利ですからね。

もう、断然Web Formですよねー。
(4) [プロジェクト]-[新しい項目の追加]で「HTMLページ」を選択し、名前(私はForgeViewer.html)をつけて[追加]します。
HTMLページを追加
さあ、準備はできました。

Basic Viewerチュートリアルをフォローしてみる

ビューアを使用するチュートリアルがありますので、これをフォローしてみます。

始める前に!

まず、表示したいデータのurnを取得します。これは前回表示用にSVF形式に変換しましたが、このとき返されたURNを使用します。
URNは変換時のものを使う

またアクセストークンを「data:read」で取得する必要があります。

Step1:HTMLファイルを準備しよう!


次の内容を先ほど準備したHTMLファイルにコピーしてください


<head>
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=no" />
    <meta charset="utf-8">

    <!-- The Viewer CSS -->
    <link rel="stylesheet" href="https://developer.api.autodesk.com/viewingservice/v1/viewers/style.min.css" type="text/css">

    <!-- Developer CSS -->
    <style>
        body {
            margin: 0;
        }
        #MyViewerDiv {
            width: 100%;
            height: 100%;
            margin: 0;
            background-color: #F0F8FF;
        }
    </style>
</head>
<body>

    <!-- The Viewer will be instantiated here -->
    <div id="MyViewerDiv"></div>

    <!-- The Viewer JS -->
    <script src="https://developer.api.autodesk.com/viewingservice/v1/viewers/three.min.js"></script>
    <script src="https://developer.api.autodesk.com/viewingservice/v1/viewers/viewer3D.min.js"></script>

    <!-- Developer JS -->
    <script>
        var viewer;
        var options = {
            env: 'AutodeskProduction',
            accessToken: '<YOUR_APPLICATION_TOKEN>'
        };
        var documentId = 'urn:<YOUR_URN_ID>';
        Autodesk.Viewing.Initializer(options, function onInitialized(){
            Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
        });

        /**
        * Autodesk.Viewing.Document.load() success callback.
        * Proceeds with model initialization.
        */
        function onDocumentLoadSuccess(doc) {
            // A document contains references to 3D and 2D viewables.
            var viewables = Autodesk.Viewing.Document.getSubItemsWithProperties(doc.getRootItem(), {'type':'geometry'}, true);
            if (viewables.length === 0) {
                console.error('Document contains no viewables.');
                return;
            }
            // Choose any of the avialble viewables
            var initialViewable = viewables[0];
            var svfUrl = doc.getViewablePath(initialViewable);
            var modelOptions = {
                sharedPropertyDbPath: doc.getPropertyDbPath()
            };
            var viewerDiv = document.getElementById('MyViewerDiv');
            viewer = new Autodesk.Viewing.Private.GuiViewer3D(viewerDiv);
            viewer.start(svfUrl, modelOptions, onLoadModelSuccess, onLoadModelError);
        }

        /**
         * Autodesk.Viewing.Document.load() failuire callback.
         */
        function onDocumentLoadFailure(viewerErrorCode) {
            console.error('onDocumentLoadFailure() - errorCode:' + viewerErrorCode);
        }

        /**
         * viewer.loadModel() success callback.
         * Invoked after the model's SVF has been initially loaded.
         * It may trigger before any geometry has been downloaded and displayed on-screen.
         */
        function onLoadModelSuccess(model) {
            console.log('onLoadModelSuccess()!');
            console.log('Validate model loaded: ' + (viewer.model === model));
            console.log(model);
        }

        /**
         * viewer.loadModel() failure callback.
         * Invoked when there's an error fetching the SVF file.
         */
        function onLoadModelError(viewerErrorCode) {
            console.error('onLoadModelError() - errorCode:' + viewerErrorCode);
        }

    </script>
</body>


追加したHTMLファイルのVisual Studioが作成した既存の内容を削除して、単純にこの文字列を上書きします。いろいろ書いていますが、とりあえず気にしないで、36行目と38行目にある<YOUR_APPLICATION_TOKEN>と<YOUR_URN_ID>をアクセストークンとdata:readで取得したアクセストークンで置き換えます。「<」「>」も含めて置き換えます。
<>を置き換える
この後にError Codes とか Step 2がありますが、いまのところこれは無視!早速グーグルクロームで実行してみましょう。アクセストークンの期限が切れていなければ、もうデータを見ることができるはずです。
見えた―!!!!(^◇^)
おお!こりゃあすごい!なんと安直な!いったいどんな理屈なんでしょうねぇ。ちょっと<script>セクションの中を見てみますか。

スクリプトは何を言っているのか?


JavaScriptは基本的に「上から順番に読み込んで実行する」というお約束なので、<script>セクションを上からチェックしてみます。

        var viewer;
        var options = {
            env: 'AutodeskProduction',
            accessToken: '<YOUR_APPLICATION_TOKEN>'
        };
        var documentId = 'urn:<YOUR_URN_ID>';

これは「viewer」「option」「documentid」の変数を宣言しているだけのようですね。問題は次の一文です。

        Autodesk.Viewing.Initializer(options, function onInitialized(){
            Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
        });

次の行がFORGEビューアの初期化を行っています。このAutodesk.Viewing.Initializerのヘルプを見てみると

Autodesk.Viewing.Initializer (options, callback)


となっています。これは「optionsの条件でFORGEビューアを初期化して、それが終わったらcallbackに定義された関数を呼び出せ!」と言っているのです。

options ~ 初期化条件設定

env      (string)

Development Staging Production の三つから選択するのですが、ふつうはProductionです。一般ユーザーの我々は、一番安定している Productionを選ぶか、何も指定しないのがよいです。チュートリアルで指定しているAutodesk Production はもう過去の遺物なので、この行は削除していいです。

getAccessToken     (function)

アクセストークンには有効時間があります。アクセストークンを非同期的に取得する関数をつくってここに指定しておけば、指定した時間が来ればこの関数を呼び出してアクセストークンを取り直す。この内容はチュートリアルのStep2に書かれているのですが、じゃあどういう関数を書けばいいのか?ということについては何も記述されていない。そんなことは自分で考えなさい、ということですかね。というわけで、今はパス。

accessToken  (string)

アクセストークンを文字列で指定。

language  (string)

言語。日本語はjaなので、ちょっと改造して language: 'ja' をoptionsに加えてみてもいいでしょうが特に記述しなくても勝手に日本語になるみたいです。

callback ~ 初期化に成功したらこの関数を実行しなさい!

チュートリアルの場合はこの引数に

function onInitialized(){
            Autodesk.Viewing.Document.load(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);

という、関数リテラルを指定しています。関数がどこでも定義できてしまうのもjavascriptの良いところ?なんでしょうかねぇ。なんかバラバラしてどこに何があるんだかわかりゃしないよ。

このコールバック関数はさらにAutodesk.Viewing.Documentloadを呼び出しています。

Autodesk.Viewing.Document.load(documentId,
                                                onSuccessCallback,
                                                onErrorCallback,
                                                accessControlProperties)

ビューアにデータをロードする関数です。引数の内容はヘルプの下のほうに書いていますが、大体の内容は以下のようになります。

documentid

これは例のurnを指定します。

onSuccessCallback

成功した時はこれを実行しなさい、という関数。このチュートリアルではonDocumentLoadSuccessという関数。<script>セクションで定義されています。ざっくりいうと、アップロードしたファイルに表示可能なビューが一つ以上ある場合、その中から最初のビューを取り出してそれをビューアに表示しましょう!という内容です。これはStep3で詳しく見てみます。

onErrorCallback

失敗した時はこれを実行しなさい、という関数。このチュートリアルではonDocumentLoadFailureという関数。実際の定義(上の緑の部分)を見てみると、エラー情報をブラウザのコンソールに情報を出力するという簡単な内容になっています。

accessControlProperties

これはよくわかりませんねー。Descriptionにもoptionalとなっているし、チュートリアルでも指定していません。わかり次第追記しますので、今回はパス。



何と意外に簡単にビューアに表示できるではないですか。この調子でもう少しチュートリアルを掘り下げてみれば、主要な関数は理解できそうな気がします。


2016年12月21日水曜日

ビューア用に変換する

アップロードしたファイルの変換

FORGEビューアで見ることができるファイルフォーマットは多数ありますが、それはそのファイルを直接見ているのではなく、ビューア用に変換する必要があります。その拡張子はどうやら「svf」という形式のようで、この変換は

Model Derivative API

で行います。デリバティブってなんか危なっかしい響きがありますが、大丈夫なんですかね。その方法を説明したチュートリアルがあります。

Prepare a File for the Viewer

その前に!(Before you begin)やるべきことがあります。
(1) アクセストークンを「data:write」と「data:read」で取得しましょう。
(2) ファイルをアップロードして(前回やりました) objectIdのURNをメモしておいてください。

だそうです。(1)はもう慣れたと思いますが、ポイントはスコープを二つ使うということです。DHCを起動しましょう。

変換用のアクセストークンの取得

いちいちアクセストークンを適切なスコープで取得することが重要なポイントとなります。ヘルプにはこのように書いてあります。
DHCの設定は次の図のようになりますが、

ポイントはSCOPEのところに

data:write data:read

と半角スペースでつないで二つのスコープを入れることです。
scopeをdata:write data:read の二つを設定


これで、SENDボタンを押すと、いつものようにアクセストークンが返ってきます。
{
"access_token": "LBBv4IgAg4qhe7P1zaRJcff6f3VK",
"token_type": "Bearer",
"expires_in": 86399
}


変換命令を送る(Model Derivative API)

アクセストークンを取得できたら、前回アップロードしたファイルをSVF形式に変換します。この掟はヘルプに書いてあります。まずはRequestですが

Method and URIPOST https://developer.api.autodesk.com/modelderivative/v2/designdata/job
これは単純に送信先にPOSTするということですから、DHCとしては

次にヘッダーです。
AuthorizationyesstringMust be Bearer <token>, where <token> is obtained via OAuth
Content-TypeyesstringMust be application/json
<token>は先ほど取得したアクセストークンを使います。ですから、DHCのヘッダーは
ヘッダーの設定
となります。
問題はBODYセクションですが、なんだかこむつかしいことが書かれています。
inputyesobjectGroup of inputs
input.urnyesstringThe design URN; returned when uploading the file to Forge The URN needs to be `Base64 (URL Safe) encoded`_span>.




outputyesstringGroup of outputs
output.formatsyesarray: objectGroup of requested formats/types. User can request multiple formats.
formats.typeyesstringThe requested output types. Possible values: DWG, FBX, IFC, IGES, OBJ, STEP, STL, SVF, thumbnail. For a list of supported types, call the GET formats endpoint.
必ず必要なところだけ取り出してみました。JSON形式で書けばいいのですが、なんだかよくわかりませんねぇ。どうやらinputというセクションの中にurnというセクションを入れ子にして作りなさい、という意味らいいです。
従いまして

{
      "input" : {
                   "urn" : Base64でエンコードされたオブジェクト(アップロードしたファイルのobjectid)のurn
                   },
というように書きます。これはこのサイトを使って、前回取得したurnをエンコードします。
urn:の文字も含んでENCODEボタンで変換する。
謎の文字列が表示される
エンコード後の文字はなんだか意味不明ですが、この文字列でオブジェクト(アップロードしたファイル)を指定します。

またoutput.formatsですが、「どんな形式に変換したいのか?」の情報を記入します。これはいろいろなフォーマットを指定できますが、SVFの場合はさらにどんなビューを変換するのかを指定します。
Viewsyesarray: stringRequired options for SVF type. Possible values: 2d, 3d
指定できるのは2dと3dだけですが、これらを[ ]でくくって指定できます。従いまして、Bodyの部分は例えば以下のようになります。{  "input" : {    "urn" : ”dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6YmxhY2tzbWl0aGJ1Y2tldDEyMDMvc2FtcGxlcHJvamVjdDAxLnJ2"  },  "output" : {    "formats" : [      {        "type" : "svf",        "views" : ["2d", "3d"]      }    ]  }}

"output" : [{"type":"svf", "view":["2d","3d"]}]の指定がちょっと特徴的ですが、JSON形式なので、]や}がチャンと対になっているように気を付けてください。DHCの画面は次のようになります。
: { [を間違えないように
これでSendを押すと200OKの値が返ってくるはずです。
200OK     (゜-゜)気持ちいい!
変換命令が受けつけられました。




今どんな感じ?

変換が開始されましたが、それには時間がかかります。お仕事の進行状況を問い合わせて、データが準備できたかどうか確認してみましょう。
ヘルプはこちら。

こちらは現在のオブジェクトの状態を問い合わせるAPIです。使い方はとても単純で
Method and URIGET https://developer.api.autodesk.com/modelderivative/v2/designdata/:urn/manifest
Authentication Contextapp only
Required OAuth Scopesdata:read
Data FormatJSON
これは単純に、URIの「:urn」の部分を、上記のurnに入れ替えて、data:readのアクセストークンを使ってGETするだけです。以下はDHCの設定です。ヘッダーにはAuthorizationに「Bearer アクセストークン」のいつものパターンですね。
長ーいendpoint

やたらと長いendpointになりますねー。この例では
developer.api.autodesk.com/modelderivative/v2/designdata/dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6YmxhY2tzbWl0aGJ1Y2tldDEyMDMvc2FtcGxlcHJvamVjdDAxLnJ2dA/manifest

となりました。レスポンスは
{
"type": "manifest",
"hasThumbnail": "true",
"status": "success",
"progress": "complete",
"region": "US",
"urn": "dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6YmxhY2tzbWl0aGJ1Y2tldDEyMDMvc2FtcGxlcHJvamVjdDAxLnJ2dA",
"version": "1.0",
[
{"name": "sampleproject01.rvt", "hasThumbnail": "true", "status": "success", "progress": "complete",…},
{"status": "success", "progress": "complete", "outputType": "thumbnail", "children":[{"guid": "0576ce39-e54e-369e-da0e-7a306abf2144",…}
]
ですので、progress はcompleteなので、変換はすでに終わったようです。

じゃあ、いよいよビューアで表示してみますか!