例とユースケース

屋内地図は、Navigateライセンスでのみ使用できます。

例とユースケース

HERE SDK を使用して、屋内地図と施設を効果的に活用するための実用的な例とユースケースを確認してください。このセクションでは、屋内地図機能を最大限に活用するためのさまざまなトピックを取り上げます。

すべての屋内地図を一覧表示する

HERE SDK for Android (Navigate) を使用すると、アカウントと選択したコレクションでアクセス可能なすべての民間施設を一覧表示できます。VenueMapには、施設識別子、施設ID、施設名を含むVenueInfo要素を保持するリストが含まれます。

List<VenueInfo> venueInfo = venueEngine.getVenueMap().getVenueInfoList();
for (int i = 0; i< venueInfo.size(); i++) {
    Log.d(TAG, "Venue Identifier: " + venueInfo.get(i).getVenueIdentifier() + " Venue Id: "+venueInfo.get(i).getVenueId() + " Venue Name: "+venueInfo.get(i).getVenueName());
}

施設IDがUUIDの地図の場合、getVenueId()は0を返します。

施設を読み込んで表示する

HERE SDK for Android (Navigate) を使用すると、Identifierごとに施設を読み込んで視覚化できます。現在の資格情報セットの施設IDを知っている必要があります。施設を読み込んで視覚化する方法は複数あります。

VenueMapには、マップに施設を追加する2つのメソッド、selectVenueAsync()addVenueAsync()があります。どちらのメソッドでも、getVenueService().addVenueToLoad()を使用してIdentifierで施設を読み込み、それをマップに追加します。メソッドselectVenueAsync()では施設も選択します。

venueEngine.getVenueMap().selectVenueAsync(String venueIdentifier);
venueEngine.getVenueMap().addVenueAsync(String venueIdentifier);

int型の施設IDを使用するレガシーマップの場合、VenueMapは引き続きselectVenueAsync(int venueID)およびaddVenueAsync(int venueID)をサポートしており、施設IDで施設を読み込みます。

施設が読み込まれると、VenueServiceVenueMapListener.onGetVenueCompleted()メソッドを呼び出します。

// Listener for the venue loading event
private final VenueMapListener venueMapListener = (venueIdentifier, venueModel, online, venueStyle) -> {
    if (venueModel == null) {
        Log.e(TAG, "Failed to load the venue: " + venueIdentifier);
    }
};

int型の施設IDを使用するレガシーマップの場合、VenueServiceVenueListener.onGetVenueCompleted(venueID, venueModel, online, venueStyle)メソッドを呼び出します。

施設が正常に読み込まれると、addVenueAsync()メソッドを使用している場合は、VenueMapLifecycleListener.onVenueAdded()メソッドのみがトリガーされます。selectVenueAsync() メソッドを使用している場合は、VenueSelectionListener.onSelectedVenueChanged() メソッドもトリガーされます。

// Listener for the venue selection event.
private final VenueSelectionListener venueSelectionListener =
    (deselectedVenue, selectedVenue) -> {
        if (selectedVenue != null) {
            // Move camera to the selected venue.
            GeoCoordinates venueCenter = selectedVenue.getVenueModel().getCenter();
            final double distanceInMeters = 500;
            MapMeasure mapMeasureZoom = new MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters);
            mapView.getCamera().lookAt(
                    new GeoCoordinates(venueCenter.latitude, venueCenter.longitude),
                    mapMeasureZoom);
            // This functions is used to facilitate the toggling of topology visibility.
            // Setting isTopologyVisible property to true will render the topology on scene and false will lead to hide the topology.
            selectedVenue.setTopologyVisible(true);
        }
    };

VenueVenueMapから削除することもでき、これによりVenueMapLifecycleListener.onVenueRemoved(venueIdentifier)メソッドがトリガーされます。

venueEngine.getVenueMap().removeVenue(venue);

int型の施設IDを使用するレガシーマップの場合、addVenueAsync()メソッドを使用するとVenueLifecycleListener.onVenueAdded()メソッドがトリガーされます。
int型の施設IDをVenueMapから削除すると、VenueLifecycleListener.onVenueRemoved(venueID)がトリガーされます。

ラベルテキストの優先設定

施設のデフォルトのラベル テキスト設定を上書きできます。

VenueEngineが初期化されると、コールバックが呼び出されます。この時点から、VenueService にアクセスできるようになります。オプションのメソッド setLabeltextPreference() を呼び出して、レンダリング中にラベル テキストの設定を行うことができます。デフォルトのスタイル ラベル テキスト優先設定をオーバーライドすると、順序によって優先設定が定義されるリストとして次のオプションを設定できます。

  • "OCCUPANT_NAMES"
  • "SPACE_NAME"
  • "INTERNAL_ADDRESS"
  • "SPACE_TYPE_NAME"
  • "SPACE_CATEGORY_NAME"

これらは任意の順序で設定できます。たとえば、ラベル テキストの優先設定に "OCCUPANT_NAMES" が含まれない場合は、リストの順序に基づいて "SPACE_NAME" などに切り替わります。優先設定が見つからない場合は何も表示されません。

private void onVenueEngineInitCompleted() {
    // Get VenueService and VenueMap objects.
    VenueService service = venueEngine.getVenueService();
    VenueMap venueMap = venueEngine.getVenueMap();

    // Add needed listeners.
    service.add(serviceListener);
    service.add(venueListener);
    venueMap.add(venueSelectionListener);

    // Start VenueEngine. Once authentication is done, the authentication callback
    // will be triggered. After, VenueEngine will start VenueService. Once VenueService
    // is initialized, VenueServiceListener.onInitializationCompleted method will be called.
    venueEngine.start((authenticationError, authenticationData) -> {
        if (authenticationError != null) {
            Log.e(TAG, "Failed to authenticate, reason: " + authenticationError.value);
        }
    });

    if(HRN != "") {
        // Set platform catalog HRN
        service.setHrn(HRN);
    }

    // Set label text preference
    service.setLabeltextPreference(LabelPref);
}

施設の図面と階を選択する

Venue オブジェクトを使用すると、施設の状態を制御できます。

メソッド getSelectedDrawing()setSelectedDrawing() を使用すると、地図上に表示される描画を取得および設定できます。新しい描画が選択されると、VenueDrawingSelectionListener.onDrawingSelected() メソッドがトリガーされます。

以下に、ListView でアイテムをクリックしたときに描画を選択する方法の例を示します。

@Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
    VenueModel venueModel = venue.getVenueModel();
    // Set the selected drawing when a user clicks on the item in the list.
    venue.setSelectedDrawing(venueModel.getDrawings().get(position));
}

メソッド getSelectedLevelIndex() および setSelectedLevelIndex() を使用すると、レベルのリスト内の位置に基づいてレベルを取得および設定できます。新しいレベルが選択されると、VenueLevelSelectionListener.onLevelSelected() メソッドがトリガーされます。

以下は、ListViewの反転レベルリストに基づいてレベルを選択する方法の例を示しています。

listView.setOnItemClickListener((parent, view, position, id) -> {
    if (venueMap.getSelectedVenue() != null) {
        // Revers an index, as levels in LevelSwitcher appear in a different order
        venueMap.getSelectedVenue().setSelectedLevelIndex(maxLevelIndex - position);
    }
});

描画とレベルを制御するUIスイッチャーの完全な例は、GitHubにある「IndoorMap」サンプルアプリで入手できます。

施設のスタイルをカスタマイズする

VenueGeometry オブジェクトのビジュアル スタイルを変更できます。ジオメトリー スタイル オブジェクトやラベル スタイル オブジェクトを作成して、Venue.setCustomStyle() メソッドに提供する必要があります。

private final VenueGeometryStyle geometryStyle = new VenueGeometryStyle(
        SELECTED_COLOR, SELECTED_OUTLINE_COLOR, 1);
private final VenueLabelStyle labelStyle = new VenueLabelStyle(
        SELECTED_TEXT_COLOR, SELECTED_TEXT_OUTLINE_COLOR, 1, 28);
ArrayList<VenueGeometry> geometries =
        new ArrayList<>(Collections.singletonList(geometry));
venue.setCustomStyle(geometries, geometryStyle, labelStyle);

識別子でスペースを選択する

スペース、レベル、描画の ID は getIdentifier() を使用して抽出できます。スペースの場合は spaces.getIdentifier() を呼び出します。次に、これらの ID 値を使用して、getGeometryById(String id) でレベルや描画の特定のスペースを検索します。

ArrayList<String> geometriesID;
ArrayList<VenueGeometry> geometries;
for(String id : geometriesID)
{
    VenueGeometry geometry = selectVenue.getSelectedDrawing().getGeometryById(id);
    geometries.add(geometry);
}
private final VenueGeometryStyle geometryStyle = new VenueGeometryStyle(
        SELECTED_COLOR, SELECTED_OUTLINE_COLOR, 1);
private final VenueLabelStyle labelStyle = new VenueLabelStyle(
        SELECTED_TEXT_COLOR, SELECTED_TEXT_OUTLINE_COLOR, 1, 28);
selectVenue.setCustomStyle(geometries, geometryStyle, labelStyle);

施設のタップ ジェスチャーを処理する

施設オブジェクトはタップで選択できます。まず、タップ リスナーを設定します。

mapView.getGestures().setTapListener(tapListener);

タップ リスナー内では、タップされた地理座標を VenueMap.getGeometry() メソッドと VenueMap.getVenue() メソッドのパラメーターとして使用できます。

private final TapListener tapListener = origin -> {
    deselectGeometry();

    // Get geo position of the tap.
    GeoCoordinates position = mapView.viewToGeoCoordinates(origin);
    if (position == null) {
        return;
    }

    VenueMap venueMap = venueEngine.getVenueMap();
    // Get VenueGeometry under the tapped position.
    VenueGeometry geometry = venueMap.getGeometry(position);

    if (geometry != null) {
        // If there is a geometry, put a marker on top of it.
        marker = new MapMarker(position, markerImage, new Anchor2D(0.5f, 1f));
        mapView.getMapScene().addMapMarker(marker);
    } else {
        // If no geometry was tapped, check if there is a not-selected venue under
        // the tapped position. If there is one, select it.
        Venue venue = venueMap.getVenue(position);
        if (venue != null) {
            venueMap.setSelectedVenue(venue);
        }
    }
};

private void deselectGeometry() {
    // If marker is already on the screen, remove it.
    if (marker != null) {
        mapView.getMapScene().removeMapMarker(marker);
    }
}

選択した施設、描画、またはレベルが変更された場合は、タップされたジオメトリーの選択を解除することをお勧めします。

private final VenueSelectionListener venueSelectionListener =
        (deselectedController, selectedController) -> deselectGeometry();

private final VenueDrawingSelectionListener drawingSelectionListener =
        (venue, deselectedController, selectedController) -> deselectGeometry();

private final VenueLevelSelectionListener levelChangeListener =
        (venue, drawing, oldLevel, newLevel) -> deselectGeometry();

void setVenueMap(VenueMap venueMap) {
    if (this.venueMap == venueMap) {
        return;
    }

    // Remove old venue map listeners.
    removeListeners();
    this.venueMap = venueMap;

    if (this.venueMap != null) {
        this.venueMap.add(venueSelectionListener);
        this.venueMap.add(drawingSelectionListener);
        this.venueMap.add(levelChangeListener);
        deselectGeometry();
    }
}

private void removeListeners() {

    if (this.venueMap != null) {
        this.venueMap.remove(venueSelectionListener);
        this.venueMap.remove(drawingSelectionListener);
        this.venueMap.remove(levelChangeListener);
    }
}

施設でのマップタップイベントの使用法を示す完全な例は、GitHubにある「IndoorMap」サンプルアプリで入手できます。

Indoor Routing

HERE SDK for Android (Navigate) は施設内のルートを計算し視覚化する包括的な屋内Rルート検索機能を提供します。このセクションでは、屋内ルーティング機能の設定方法と使用方法について説明します。

HEREベルリンオフィスの屋内ルート。

屋内ルートの計算

屋内ルートを計算するには、IndoorRoutingEngineを作成し、施設およびフロア情報を含む経由地を指定する必要があります。経由地は出発地点と到着地点ごとに作成します。

まず、次のようにルーティングエンジンを作成します。

IndoorRoutingEngine routingEngine = new IndoorRoutingEngine(venueEngine.getVenueService());

開始地と目的地の経由地を作成します。屋内の場所には、次のように施設IDとフロアIDを指定します。

IndoorWaypoint startWaypoint = new IndoorWaypoint(
    position,
    String.valueOf(venueModel.getIdentifier()),
    String.valueOf(venue.getSelectedLevel().getIdentifier()));

IndoorWaypoint destinationWaypoint = new IndoorWaypoint(
    position,
    String.valueOf(venueModel.getIdentifier()),
    String.valueOf(venue.getSelectedLevel().getIdentifier()));

routingEngineを使用して次のようにルートを計算します。

IndoorRouteOptions routeOptions = new IndoorRouteOptions();
engine.calculateRoute(startWaypoint, destinationWaypoint, routeOptions, 
    (routingError, routeList, routeNotices) -> {
        // Handle route notices (available even on success)
        if (routeNotices != null && !routeNotices.isEmpty()) {
            for (IndoorRouteNotice notice : routeNotices) {
                Log.d(TAG, notice.severity + ": " + notice.title);
            }
        }
        
        if (routingError == null && routeList != null) {
            Route route = routeList.get(0);
            // Use the calculated route
        }
    });

複数のフロアにまたがるルートの計算

屋内ルートは、施設内の複数のフロアにまたがることがあります。SDKはフロア間の移動を自動的に処理し、ルート内のフロア変更に関する情報を提供します。

屋内セクションの詳細およびフロア情報にアクセスするには、次のようにします。

for (Section section : route.getSections()) {
    // Check if section has indoor details
    if (section.getIndoorSectionDetails() != null) {
        IndoorSectionDetails indoorDetails = section.getIndoorSectionDetails();
        Log.d(TAG, "Indoor Section - Departure: " +
            indoorDetails.getDeparturePlace().venueId);
        Log.d(TAG, "Indoor Section - Arrival: " +
            indoorDetails.getArrivalPlace().venueId);

        // Iterate through indoor maneuvers
        for (IndoorManeuver indoorManeuver : indoorDetails.getIndoorManeuvers()) {
            if (indoorManeuver.getAction() != null) {
                Log.d(TAG, "IndoorManeuver Action: " + indoorManeuver.getAction());
            }
            Log.d(TAG, "IndoorManeuver Location Info: Level_Z_Index: " +
                indoorManeuver.getLevelZIndex());

            // Check for level change data
            if (indoorManeuver.getIndoorLevelChangeData() != null) {
                Log.d(TAG, "IndoorManeuver Level change using: " +
                    indoorManeuver.getIndoorLevelChangeData().connector +
                    " changeInLevel: " +
                    indoorManeuver.getIndoorLevelChangeData().deltaZ);
            }
        }
    }
}

IndoorLevelChangeDataは、次の情報を提供します。

  • connector:使用されるフロア間の接続手段の種類 (エレベーター、階段、エスカレーター、スロープなど)
  • deltaZ:フロアの変化量 (上方向は正、下方向は負)

エラー処理とルート通知

ルート計算コールバックでは、エラー情報とルート通知の両方が提供されます。ルート通知には、ルート計算中に発生した問題や警告に関する詳細情報が含まれますが、ルート検索は、ルート検索プロセス自体の失敗を示します。

ルート通知の処理

ルート通知は、ルート検索が正常に完了した場合でもコールバックで提供されます。これには、計算されたルートに関する重要な情報が含まれます。

engine.calculateRoute(startWaypoint, destinationWaypoint, routeOptions, 
    (routingError, routeList, routeNotices) -> {
        // Handle route notices first (available even on success)
        if (routeNotices != null && !routeNotices.isEmpty()) {
            for (IndoorRouteNotice notice : routeNotices) {
                String logMessage = notice.title;
                
                // Log based on severity
                if (notice.severity == NoticeSeverity.CRITICAL) {
                    Log.e(TAG, "CRITICAL: " + logMessage);
                } else {
                    Log.w(TAG, "INFO: " + logMessage);
                }
                
                // Handle specific notice codes
                switch (notice.code) {
                    // CRITICAL notices - route calculation failed
                    case NO_ROUTE_FOUND:
                        // No route found between waypoints
                        break;
                    case COULD_NOT_MATCH_ORIGIN:
                        // Origin waypoint could not be matched to venue topology
                        break;
                    case COULD_NOT_MATCH_DESTINATION:
                        // Destination waypoint could not be matched to venue topology
                        break;
                    
                    // INFO notices - vehicle usage violations
                    case VIOLATED_ROUTE_HEAD_CONDITION:
                        // Cannot use vehicle at route start only
                        Log.w(TAG, "Cannot use vehicle at route start - showing alternative");
                        break;
                    case VIOLATED_ROUTE_TAIL_CONDITION:
                        // Cannot use vehicle at route end only
                        Log.w(TAG, "Cannot use vehicle at route end - showing alternative");
                        break;
                    case VIOLATED_ENTIRE_ROUTE_CONDITION:
                        // Cannot use vehicle for entire route
                        Log.w(TAG, "Cannot use vehicle for entire route - showing partial usage");
                        break;
                }
                
                // Access additional details
                if (notice.details != null && !notice.details.isEmpty()) {
                    for (IndoorRouteNoticeDetails detail : notice.details) {
                        Log.d(TAG, "Detail - Type: " + detail.type + 
                                   ", Cause: " + detail.cause + 
                                   ", Title: " + detail.title);
                    }
                }
            }
        }
        
        // Handle routing errors
        if (routingError != null) {
            String errorMsg;
            switch (routingError) {
                case MAP_NOT_FOUND:
                    errorMsg = "Requested map not found";
                    break;
                case PARSING_ERROR:
                    errorMsg = "Routing response not in correct format";
                    break;
                case UNKNOWN_ERROR:
                default:
                    errorMsg = "Unknown error encountered";
                    break;
            }
            Log.e(TAG, "Routing error: " + errorMsg);
            return;
        }
        
        // Process successful route
        if (routeList != null && !routeList.isEmpty()) {
            Route route = routeList.get(0);
            // Use the calculated route
        }
    });
ルート通知コードリファレンス

次の表は、サポートされているすべてのルート通知コードを示します。

通知コード重大度カテゴリー説明
NO_ROUTE_FOUNDCRITICAL (重大)ルートの失敗選択した経由地間にルートが見つかりません
COULD_NOT_MATCH_ORIGINCRITICAL (重大)ルートの失敗出発地の経由地が施設のトポロジーと一致しませんでした
COULD_NOT_MATCH_DESTINATIONCRITICAL (重大)ルートの失敗目的地の経由地が施設のトポロジーと一致しませんでした
VIOLATED_ROUTE_HEAD_CONDITIONINFO (情報)車両違反ルートの開始地点でのみ車両を使用することはできません (ROUTE_HEAD条件に違反しています)
VIOLATED_ROUTE_TAIL_CONDITIONINFO (情報)車両違反ルートの終了地点でのみ車両を使用することはできません (ROUTE_TAIL条件に違反しています)
VIOLATED_ENTIRE_ROUTE_CONDITIONINFO (情報)車両違反ルート全体で車両を使用することはできません (ENTIRE_ROUTE条件に違反しています)
IGNORED_VEHICLE_ENABLEINFO (情報)無視されたパラメーター車両有効化オプションが無視されました (選択した移動モードには適用されません)
IGNORED_VEHICLE_SPEEDINFO (情報)無視されたパラメーター車速オプションが無視されました (選択した移動モードには適用されません)
IGNORED_VEHICLE_AVOID_FEATURESINFO (情報)無視されたパラメーター車両回避機能が無視されました
VIOLATED_TRANSPORT_MODEINFO (情報)移動モードリクエストされた移動モードを満たすことができません

:CRITICAL (重大) 通知はルート計算が失敗したことを示しています。INFO (情報) 通知は、パラメーター違反や無視されたオプションについて警告を表示しますが、ルート検索自体は正常に完了する場合があります。

フロア間の接続手段の回避オプション

屋内ルートの計算時に、ユーザーの設定やアクセシビリティ要件に基づいて、特定の種類のフロア間の接続手段を回避するようルーティングエンジンを設定できます。

IndoorRouteOptions routeOptions = new IndoorRouteOptions();

// Add features to avoid
routeOptions.indoorAvoidanceOptions.indoorFeatures.add(
    IndoorLevelChangeFeatures.ELEVATOR);
routeOptions.indoorAvoidanceOptions.indoorFeatures.add(
    IndoorLevelChangeFeatures.ESCALATOR);
routeOptions.indoorAvoidanceOptions.indoorFeatures.add(
    IndoorLevelChangeFeatures.STAIRS);

回避可能なフロア間の接続手段の種類は次のとおりです。

  • ELEVATOR:エレベーター
  • ESCALATOR:エスカレーター
  • STAIRS:階段
  • RAMP:一般的なスロープ
  • PEDESTRIAN_RAMP:歩行者専用スロープ
  • DRIVE_RAMP:車両用スロープ (車両ルート用)
  • CAR_LIFT:車両用リフト (車両ルート用)
  • ELEVATOR_BANK:エレベーター群
  • CONNECTOR:汎用接続手段

車両ルートで車両用スロープと車両用リフトを回避する場合

IndoorRouteOptions routeOptions = new IndoorRouteOptions();
routeOptions.transportMode = VenueTransportMode.CAR;

// Avoid vehicle-specific features
routeOptions.indoorAvoidanceOptions.indoorFeatures.add(
    IndoorLevelChangeFeatures.CAR_LIFT);
routeOptions.indoorAvoidanceOptions.indoorFeatures.add(
    IndoorLevelChangeFeatures.DRIVE_RAMP);

回避オプションを削除するには、次のようにします。

routeOptions.indoorAvoidanceOptions.indoorFeatures.remove(
    IndoorLevelChangeFeatures.ELEVATOR);

ルート設定

IndoorRouteOptionsオブジェクトを使用して、ルート計算の設定を行います。

ルート最適化モード

次のように、最速ルートと最短ルートから選択します。

IndoorRouteOptions routeOptions = new IndoorRouteOptions();

// For fastest route
routeOptions.routeOptions.optimizationMode = OptimizationMode.FASTEST;

// For shortest route
routeOptions.routeOptions.optimizationMode = OptimizationMode.SHORTEST;

マルチモーダル交通機関サポート

HERE SDKは、屋内ルーティングのために複数の交通機関モードをサポートしています:徒歩、車、タクシー、スクーター。交通機関特有のパラメーターはVenueTransportSpecificationを使用して設定できます。

歩行者用ルート

徒歩ルートの場合、歩行速度を設定するにはVenuePedestrianSpecificationを使用してください:

// Create pedestrian specification
VenuePedestrianSpecification pedestrianSpec = new VenuePedestrianSpecification();
pedestrianSpec.walkingSpeedInMetersPerSecond = 1.5; // Valid range: 0.5 to 2.0 m/s

// Create transport specification
VenueTransportSpecification transportSpec = new VenueTransportSpecification();
transportSpec.pedestrianSpecification = pedestrianSpec;

// Create route options
IndoorRouteOptions routeOptions = new IndoorRouteOptions();
routeOptions.transportMode = VenueTransportMode.PEDESTRIAN;
routeOptions.venueTransportSpecification = transportSpec;

車両ルート (車、タクシー、スクーター)

車両ベースのルートの場合、車両特有のパラメーターを設定します:

// Create car specification
VenueCarSpecification carSpec = new VenueCarSpecification();
carSpec.speedInMetersPerSecond = 3.0; // Valid range: 2.0 to 5.0 m/s
carSpec.enableOption = EnableOption.ROUTE_HEAD; // Use car only at route start

// Also set pedestrian spec for walking portions
VenuePedestrianSpecification pedestrianSpec = new VenuePedestrianSpecification();
pedestrianSpec.walkingSpeedInMetersPerSecond = 1.4;

// Create transport specification
VenueTransportSpecification transportSpec = new VenueTransportSpecification();
transportSpec.carSpecification = carSpec;
transportSpec.pedestrianSpecification = pedestrianSpec;

// Create route options
IndoorRouteOptions routeOptions = new IndoorRouteOptions();
routeOptions.transportMode = VenueTransportMode.CAR;
routeOptions.venueTransportSpecification = transportSpec;

同じパターンがVenueTaxiSpecificationVenueScooterSpecificationに適用されます。

車両有効オプション

EnableOption列挙型は、ルートに沿って車両が使用できる場所を制御します:

  • ROUTE_HEAD:ルートの開始時のみ車両を使用 (例:入口近くに車を駐車し、その後徒歩)
  • ROUTE_TAIL:ルートの終了時のみ車両を使用 (例:最初に徒歩、その後駐車場から運転)
  • ENTIRE_ROUTE:ルート全体で車両を使用

ルートの末尾でスクーターを使用した例:

VenueScooterSpecification scooterSpec = new VenueScooterSpecification();
scooterSpec.speedInMetersPerSecond = 5.0;
scooterSpec.enableOption = EnableOption.ROUTE_TAIL;

VenueTransportSpecification transportSpec = new VenueTransportSpecification();
transportSpec.scooterSpecification = scooterSpec;

IndoorRouteOptions routeOptions = new IndoorRouteOptions();
routeOptions.transportMode = VenueTransportMode.SCOOTER;
routeOptions.venueTransportSpecification = transportSpec;

輸送モード変更によるセクションベースのルート

車両輸送モードを持つルートは、異なる輸送モードを持つ複数のセクションを持つ場合があります:

for (Section section : route.getSections()) {
    // Get transport mode for this section
    SectionTransportMode sectionMode = section.getTransportMode();
    
    switch (sectionMode) {
        case PEDESTRIAN:
            Log.d(TAG, "Walking section");
            break;
        case CAR:
            Log.d(TAG, "Driving section");
            break;
        case TAXI:
            Log.d(TAG, "Taxi section");
            break;
        case SCOOTER:
            Log.d(TAG, "Scooter section");
            break;
    }
    
    Log.d(TAG, "Section distance: " + section.getLengthInMeters() + " meters");
}

### Turn by turn actions

Indoor routes provide detailed turn-by-turn maneuver information through the `IndoorManeuver` class.

```java
for (Section section : route.getSections()) {
    if (section.getIndoorSectionDetails() != null) {
        IndoorSectionDetails indoorDetails = section.getIndoorSectionDetails();

        for (IndoorManeuver indoorManeuver : indoorDetails.getIndoorManeuvers()) {
            // Get the maneuver action
            if (indoorManeuver.getAction() != null) {
                Log.d(TAG, "Action: " + indoorManeuver.getAction());
            }

            // Get the level information
            Log.d(TAG, "Level Z-Index: " + indoorManeuver.getLevelZIndex());

            // Check for level change information
            if (indoorManeuver.getIndoorLevelChangeData() != null) {
                Log.d(TAG, "Level change via: " +
                    indoorManeuver.getIndoorLevelChangeData().connector);
                Log.d(TAG, "Change in levels: " +
                    indoorManeuver.getIndoorLevelChangeData().deltaZ);
            }

            // Get space information (room/area details)
            if (indoorManeuver.getIndoorSpaceData() != null) {
                Log.d(TAG, "Space Category: " +
                    indoorManeuver.getIndoorSpaceData().spaceCategory);
                Log.d(TAG, "Space Type: " +
                    indoorManeuver.getIndoorSpaceData().spaceType);
            }
        }
    }
}

IndoorManeuverは次を提供します。

  • Action:実行するアクションのタイプ
  • Level Z-Index:操作が行われるフロアの階層
  • Indoor Level Change Data:接続手段の種類や移動するフロア数など、フロア間の移動に関する情報
  • Indoor Space Data:進入または通過する空間に関する詳細 (カテゴリーやタイプなど)

ルートのETAと総距離

計算されたルートから、到着予測時刻 (ETA) と総距離を取得できます。

Route route = routeList.get(0);

// Get the total duration in seconds
long durationInSeconds = route.getDuration().getSeconds();

// Get the total length in meters
int lengthInMeters = route.getLengthInMeters();

// Format for display
Log.d(TAG, "Route duration: " + durationInSeconds + " seconds");
Log.d(TAG, "Route distance: " + lengthInMeters + " meters");

// Convert to more readable format
long minutes = durationInSeconds / 60;
long seconds = durationInSeconds % 60;
double kilometers = lengthInMeters / 1000.0;

Log.d(TAG, String.format("ETA: %d min %d sec", minutes, seconds));
Log.d(TAG, String.format("Distance: %.2f km", kilometers));

セクション単位の詳細は、次のとおりです。

for (Section section : route.getSections()) {
    long sectionDuration = section.getDuration().getSeconds();
    int sectionLength = section.getLengthInMeters();

    Log.d(TAG, "Section duration: " + sectionDuration + " seconds");
    Log.d(TAG, "Section distance: " + sectionLength + " meters");
}

ルートのレンダリング

IndoorRoutingControllerは、地図上での屋内ルートの視覚化を処理します。

まず、次のようにコントローラーを作成します。

IndoorRoutingController controller = new IndoorRoutingController(venueMap, mapView);

ポリラインのレンダリング

地図上にルートを表示するには、showRoute()メソッドを使用します。

// Create route style
IndoorRouteStyle routeStyle = new IndoorRouteStyle();

// Show the route
controller.showRoute(route, routeStyle);

ルートを非表示にするには、次のようにします。

controller.hideRoute();

フロア変更アイコンの配置

さまざまなルート要素やフロア変更インジケーターのカスタムマーカーを設定します。

IndoorRouteStyle routeStyle = new IndoorRouteStyle();

// Set start and destination markers
Anchor2D middleBottomAnchor = new Anchor2D(0.5, 1.0);
MapImage startImage = MapImageFactory.fromResource(
    context.getResources(), R.drawable.ic_route_start);
MapMarker startMarker = new MapMarker(
    new GeoCoordinates(0.0, 0.0), startImage, middleBottomAnchor);
routeStyle.setStartMarker(startMarker);

MapImage endImage = MapImageFactory.fromResource(
    context.getResources(), R.drawable.ic_route_end);
MapMarker endMarker = new MapMarker(
    new GeoCoordinates(0.0, 0.0), endImage, middleBottomAnchor);
routeStyle.setDestinationMarker(endMarker);

// Set transport mode markers
MapImage walkImage = MapImageFactory.fromResource(
    context.getResources(), R.drawable.indoor_walk);
MapMarker walkMarker = new MapMarker(
    new GeoCoordinates(0.0, 0.0), walkImage, new Anchor2D());
routeStyle.setWalkMarker(walkMarker);

MapImage driveImage = MapImageFactory.fromResource(
    context.getResources(), R.drawable.indoor_drive);
MapMarker driveMarker = new MapMarker(
    new GeoCoordinates(0.0, 0.0), driveImage, new Anchor2D());
routeStyle.setDriveMarker(driveMarker);

次のように、方向インジケーター付きのフロア変更フィーチャーのマーカーを設定します。

// Configure markers for each level change feature
IndoorLevelChangeFeatures[] features = new IndoorLevelChangeFeatures[] {
    IndoorLevelChangeFeatures.ELEVATOR,
    IndoorLevelChangeFeatures.ESCALATOR,
    IndoorLevelChangeFeatures.STAIRS,
    IndoorLevelChangeFeatures.RAMP
};

for (IndoorLevelChangeFeatures feature : features) {
    // Create markers for up, down, and neutral directions
    MapMarker upMarker = createMarkerForFeature(feature, 1);    // Going up
    MapMarker downMarker = createMarkerForFeature(feature, -1); // Going down
    MapMarker neutralMarker = createMarkerForFeature(feature, 0); // No vertical change

    routeStyle.setIndoorMarkersFor(feature, upMarker, downMarker, neutralMarker);
}

次のように、フィーチャータイプと方向に基づいてマーカーを作成するヘルパーメソッドを定義します。

private MapMarker createMarkerForFeature(IndoorLevelChangeFeatures feature, int deltaZ) {
    int resourceId = getResourceForFeature(feature, deltaZ);
    if (resourceId == 0) {
        return null;
    }

    MapImage image = MapImageFactory.fromResource(
        context.getResources(), resourceId);
    if (image != null) {
        return new MapMarker(new GeoCoordinates(0.0, 0.0), image, new Anchor2D());
    }
    return null;
}

private int getResourceForFeature(IndoorLevelChangeFeatures feature, int deltaZ) {
    switch (feature) {
        case ELEVATOR:
            if (deltaZ > 0) return R.drawable.indoor_elevator_up;
            if (deltaZ < 0) return R.drawable.indoor_elevator_down;
            return R.drawable.indoor_elevator;
        case ESCALATOR:
            if (deltaZ > 0) return R.drawable.indoor_escalator_up;
            if (deltaZ < 0) return R.drawable.indoor_escalator_down;
            return R.drawable.indoor_escalator;
        case STAIRS:
            if (deltaZ > 0) return R.drawable.indoor_stairs_up;
            if (deltaZ < 0) return R.drawable.indoor_stairs_down;
            return R.drawable.indoor_stairs;
        case RAMP:
            if (deltaZ > 0) return R.drawable.indoor_ramp_up;
            if (deltaZ < 0) return R.drawable.indoor_ramp_down;
            return R.drawable.indoor_ramp;
        default:
            return 0;
    }
}

deltaZパラメーターは次のように方向を示します。

  • 1 (正):上のフロアに移動
  • -1 (負):下の階に降りる
  • 0:上下方向のフロア変更なし

showRoute()メソッドはルートのレンダリングに関してカスタマイズの範囲が限定されています。フロアに関する高度なカスタマイズを適用する場合は、ルートの各座標間に描画されるMapPolylineを使用します。「地図上にルートを表示する」を参照してください。

施設を含む屋内ルート検索の使用方法を示す完全な例は、GitHubにある「IndoorMap」サンプルアプリで確認できます。


このページは役に立ちましたか?