Thursday Jul 21, 2016

How to deploy MapViewer 12.2.1.1.0 on WLS (without JRF)

The linked document (pdf) describes how to deploy MapViewer 12.2.1.1.0 in Weblogic (12.2.1.1). The document provides more details but the basic steps are:

  • Download and install WLS - can be the generic or the infrastructure FMW installer file
  • Run the WLS config wizard to create a domain.

  • Download MapViewer 12.2.1.1.0 ear file for WebLogic.

  • Start WebLogic domain.

  • Use WLS console to deploy the MapViewer 12.2.1.1.0 WLS specific ear.


Monday Jul 18, 2016

Oracle Maps V2 API: Dynamic Tile Layer (supersedes previous entry)

Oracle Maps V2 API: Dynamic Tile Layer

by Honglei Zhu & Carol Palmer

This is an updated post with new APIs in 12.2.1.1.

Overview

Dynamic tile layer, a feature in Oracle Maps V2 API, is now available. This feature is very useful for visual analysis in big data analytics. Because a dynamic tile layer does not rely on Oracle Maps server metadata to define the tile layer, client side map applications can define and create tile layers according to ad-hoc demand dynamically. Capabilities include:

· client application can define dynamic tile layers directly, not relying on pre-defined tile layers on the server side. Because it is independent from Oracle Maps server metadata definition for tile layers, any number of dynamic tile layers can be created on the client side.

· dynamic tile layer may fetch map images from either an Oracle Maps server or from a third party map service provider.

· client application may provide a URL-generation function to specify where its tile images are to be fetched.

How it works

In a map application, a dynamic tile layer is created in a similar way as a regular tile layer, but with different parameters. Behind the scenes, the differences are fundamental.

To illustrate their similarities and differences, a regular tile layer definition is given first as follows:

Assume a variable baseURL is properly defined and the specified dataSource and tileLayer exist. A regular tile layer can be defined and instantiated (see code snippet below). The tile layer instance can then be added into the client map application.

Code snippet for a regular tile layer: a regular tile layer definition.

var regular_tilelayer = new OM.layer.TileLayer("tilelayer",

{

tileServerURL:baseURL+"/mcserver",

dataSource:"mvdemo",

tileLayer:"demo_map"

});

In the above code snippet, the tile layer map images will be fetched from an Oracle Maps cache server (i.e., the /mcserver suffix in the tileServerURL property) from the given dataSource (mvdemo). The tile layer (demo_map) should have been defined in Oracle Maps server metadata in view USER_SDO_CACHED_MAPS.

Below several examples show how to create a dynamic tile layer. To define a dynamic tile layer, you need to create a Tile Layer Config instance and a universe instance. You may use a built-in universe from the V2 API or create your own. For simplicity and to save space, the examples use a built-in universe. A Tile Layer Config instance only needs to define the dimension of an image tile, and 256 pixels for a tile image's width and height are commonly adopted. The following code snippet creates those two instances and will be referenced by all dynamic tile layer examples.

Code snippet for universe and config: creating a universe and a Tile Layer Config instance.

var myuniv= new OM.universe.LatLonUniverse();

var myconfig=new OM.layer.TileLayerConfig(

{

tileImageWidth: 256,

tileImageHeight: 256

});

Example 1: A dynamic tile layer that fetches map images from an Oracle Maps server and has its map contents defined by a server basemap.

Code snippets for example 1: A dynamic tile layer based on a server basemap.

Step1: create a ServerMapRequest instance and set its properties

var req = new OM.server.ServerMapRequest(baseURL);

req.setProperties({

dataSource:"MVDEMO",

basemap: 'demo_map',

transparent:true,

antialiase:"false",

});

Step 2: create an object containing properties of this dynamic tile layer

var dtl_props = {

universe: myuniv,

tileLayerConfig: myconfig,

tileServerURL: baseURL + "/omserver",

enableUTFGrid: true,

enableUTFGridInfoWindow: true,

utfGridResolution: 4

};

Step 3: create a dynamic tile layer

var dynamic_tilelayer_1 = new OM.layer.DynamicTileLayer("dynamic_tl1", dtl_props, req);

In the above example in step 2, the string value in variable tileServerURL is pointing to an Oracle Maps server (i.e., the /omserver suffix in the tileServerURL property) of a server instance. The variable baseURL, as required by a regular tile layer, is defined in the same way as it would be for a regular tile layer. This baseURL may point to the same server as where the web mapping application is deployed, or point to another Oracle Maps server instance. For example, it can be in a form of (a) or (b) below:

(a) From the same Oracle Maps server instance:

var baseURL=document.location.protocol+"//"+document.location.host+"/mapviewer";

(b) From another Oracle Maps server instance:

var baseURL="http://myapp.mycorp.com/mapviewer ";

From this example, you notice that three statements are given to create a dynamic tile layer: 1) create a map request instance, ServerMapRequest; 2) create an JSON object to contain the dynamic tile layer related properties; and 3) instantiate a dynamic tile layer.

As shown in the code snippet, a dynamic tile layer does not need a tile layer to be pre-defined in Oracle Maps server metadata, i.e., it does not need a row in view USER_SDO_CACHED_MAPS.

Another significant difference is that a regular tile layer (see code snippet for a regular tile layer) fetches map images from an Oracle Maps cache server (mcserver, which retrieves map tiles from its disk-cache), but a dynamic tile layer (see code snippet for example 1) requests map images from an Oracle Maps map server (omserver, which renders a fresh map image and does not disk-cache images).

Because of this difference, a regular tile layer may demand large storage space for disk-caching if a large number of regular tile layers are created. It will be an insufficient use of storage resources if the cached images are not likely to be requested again.

Example 2: A dynamic tile layer that fetches map images from an Oracle Maps server and has its map contents defined by server themes.

Code snippets for example 2: A dynamic tile layer based on a list of predefined themes.

Step1: create a ServerMapRequest instance and set its properties

var req = new OM.server.ServerMapRequest(baseURL);

req.setProperties({

dataSource:"MVDEMO",

transparent:true,

antialiase:"false",

});

var t1 = new OM.server.ServerPredefinedTheme("THEME_DEMO_STATES");

var t2 = new OM.server.ServerPredefinedTheme("THEME_DEMO_HIGHWAYS");

var t3 = new OM.server.ServerPredefinedTheme("THEME_DEMO_CITIES");

req.addThemes([t1, t2, t3]);

Step 2: create an object containing properties of this dynamic tile layer

var dtl_props = {

universe: myuniv,

tileLayerConfig: myconfig,

tileServerURL: baseURL + "/omserver",

enableUTFGrid: true,

enableUTFGridInfoWindow: true,

utfGridResolution: 4

};

Step 3: create a dynamic tile layer

var dynamic_tilelayer_2 = new OM.layer.DynamicTileLayer("dynamic_tl2", dtl_props, req);

Comparing this example with Example 1, you notice that instead of specifying a server basemap, the ServerMapRequest instance adds some predefined themes. From a practical perspective, it offers the flexibility of creating tile layers based on available predefined themes. In other words, a client side defined dynamic tile layer may only depend on some rows in server metadata in view USER_SDO_THEMES.

Example 3: A dynamic tile layer that fetches map images from an Oracle Maps server and its map contents are dynamically specified using Oracle spatial tables.

Code snippets for example 3: A dynamic tile layer based on spatial tables.

Step 1: create a style

var myc1 = new OM.style.Color({

styleName: "mycolor1",

stroke: "#333333",

strokeOpacity: 1.0,

fill: "#F2EFE9",

fillOpacity: 1.0

});

Step 2: create a JDBC theme and set its properties

var jdbcTStates= new OM.server.ServerJDBCTheme('theme_jdbc_states');

jdbcTStates.setDataSourceName('mvdemo');

jdbcTStates.setSRID('8307');

jdbcTStates.setGeometryColumnName('geom');

var sql='select totpop, poppsqmi, state, state_abrv, geom from states';

jdbcTStates.setQuery(sql);

jdbcTStates.addInfoColumn({column: 'state_abrv', name:'State'});

jdbcTStates.addInfoColumn({column: 'totpop', name:'Population'});

jdbcTStates.addInfoColumn({column: 'poppsqmi', name:'Pop. Density'});

jdbcTStates.setRenderingStyleName('mycolor1');

Step 3: create a ServerMapRequest instance and set its properties

var req = new OM.server.ServerMapRequest(baseURL);

req.setProperties({

dataSource:"MVDEMO",

transparent:true,

antialiase:"false",

});

var t1 = new OM.server.ServerPredefinedTheme("THEME_DEMO_STATES");

var t2 = new OM.server.ServerPredefinedTheme("THEME_DEMO_HIGHWAYS");

var t3 = new OM.server.ServerPredefinedTheme("THEME_DEMO_CITIES");

req.addTheme(jdbcTStates);

req.addStyle(myc1);

Step 4: create an object containing properties of this dynamic tile layer

var dtl_props = {

universe: myuniv,

tileLayerConfig: myconfig,

tileServerURL: baseURL + "/omserver",

enableUTFGrid: true,

enableUTFGridInfoWindow: true,

utfGridResolution: 4

};

Step 5: create a dynamic tile layer

var dynamic_tilelayer_3 = new OM.layer.DynamicTileLayer("dynamic_tl3", dtl_props, req);

In this example, a dynamically defined style and ServerJDBCTheme object are created first. They are then used by the addTheme and addStyle methods of a ServerMapRequest object.

Example 4: A dynamic tile layer that fetches map images from a third party map service provider; map image URLs are generated by a client provided JavaScript function.

Code snippets for example 4: A dynamic tile layer's map image URLs are defined by a client provided function.

Step 1: create a URL construction function

var urlb = function (w, h, minX, minY, maxX, maxY, options){

var str="http://my.mycorp.com:8080/geoserver/ows?";

var optParams="";

str = str+"request=getmap"+

"&bbox="+minX+","+minY+","+maxX+","+maxY+

"&width="+w+

"&height="+h;

if (!OM.isNull(options)){

for (var key in options){

optParams=optParams +"&"+key +"="+options[key];

}

}

return str+optParams;

}

Step 2: create an object containing properties of this dynamic tile layer

var dtl_props = {

universe: myuniv,

tileLayerConfig: myconfig,

urlBuilder: urlb,

urlBuilderOptions: {

"layers": "topp:states,sf:sfdem,sf:roads,sf:streams",

"CRS": "CRS:84",

"service": "WMS",

"version": "1.3.0",

"format": "image/png"

}

};

Step 3: create a dynamic tile layer

var dynamic_tilelayer_4 = new OM.layer.DynamicTileLayer("dynamic_tl4", dtl_props);

In this example, a dynamic tile layer instance (i.e., dynamic_tilelayer_4) contains a "urlBuilder" property to provide a URL generation function (i.e., urlb). The URL generation function will be used by the dynamic tile layer for fetching image tiles from the specified map service provider. This code snippet uses a third party map provider, a GeoServer instance, to provide map images. Additional map service provider required parameters can be provided in the "urlBuilderOptions" property. In this example, it specifies several additional parameters, "layers", "CRS", "service", "version", and "format", needed by the server.

Example 5: A dynamic tile layer use case.

Code snippet for example 5: A dynamic tile layer use case based on Oracle Maps server.

Step1: get the "where" clause from an application's UI from a function, getWhereClauseFromUI(), assuming this function is provided by an application.

var wherec = getWhereClauseFromUI();

Step2: create a JDBC theme and set its properties

var objJDBCTheme= new OM.server.ServerJDBCTheme();

objJDBCTheme.setDataSourceName('storm');

objJDBCTheme.setSRID('3857');

objJDBCTheme.setXColumnName('long_loc');

objJDBCTheme.setYColumnName('lat_loc');

objJDBCTheme.addInfoColumn({column: 'YEAR', name:'Year'});

objJDBCTheme.addInfoColumn({column: 'MONTH', name:'Month'});

objJDBCTheme.addInfoColumn({column: 'DAY', name:'Day'});

objJDBCTheme.addInfoColumn({column: 'STATE', name:'State'});

objJDBCTheme.addInfoColumn({column: 'LOSS', name:'Loss'});

objJDBCTheme.addInfoColumn({column: 'CROPLOSS', name:'Crop_loss'});

objJDBCTheme.addInfoColumn({column: 'FATALITIES', name:'Fatalities'});

objJDBCTheme.addInfoColumn({column: 'INJURIES', name:'Injuries'});

objJDBCTheme.setName('theme_tornado');

objJDBCTheme.setQuery("SELECT s.geom.sdo_point.x long_loc,s.geom.sdo_point.y lat_loc,year,month,day,state,fatalities,injuries,loss,croploss from tornado_3857 s"+

(wherec === "" ?"": wherec));

objJDBCTheme.setRenderingStyleName('V.TORNADO');

Step 3: create a ServerMapRequest instance and set its properties

var req = new OM.server.ServerMapRequest(baseURL);

req.setProperties({

dataSource:'storm',

transparent:true,

antialiase:"false",

});

req.addTheme(objJDBCTheme);

Step 4: create an object containing properties of this dynamic tile layer

var dtl_props = {

universe: myuniv,

tileLayerConfig: myconfig,

tileServerURL: baseURL + "/omserver",

enableUTFGrid: true,

enableUTFGridInfoWindow: true,

utfGridResolution: 4

};

Step 5: create a dynamic tile layer

var tornado_damage = new OM.layer.DynamicTileLayer("tornado_damage", dtl_props, req);

The above code snippet of a dynamic tile layer use case illustrates the following characteristics:

1) The map application fetches map images from an Oracle Maps server. Therefore, takes advantage of all available features from an Oracle Maps server.

2) The map image is set to be transparent (i.e., the value for property "transparent" is true). This setting makes all of the non-overlapping features visible when multiple dynamic tile layers are displayed. For example, when you overlay a 'tornado_damage' layer on top of a 'hail_damage' layer, you may see both layers on the map when event locations are not overlapping. This setting is more useful for multiple layers containing linear and point features. Note that since the V2 API allows you to turn on/off a layer's visibility, you can always make a layer of interest standout and visible in your application.

3) The dynamic tile layer also enables Oracle Maps server's UTFGrid support (i.e., the value for property "enableUTFGrid" is true with a resolution of 4 be specified as the value of property " utfGridResolution "). This setting instructs V2 API to request an additional file as a companion of a map tile image. The file contains a JSON object to provide a two-dimensional grid that matches the tile image plus some text attributes for each grid cell. When a mouse event is triggered (e.g., a mouse click) at an image pixel, its corresponding grid cell can then be located and thus the text attributes of that grid cell can be retrieved and displayed in the info window.

The text attributes in a JSON document is defined in a server theme's <hidden_info> element. The theme can be either a predefined geometry theme or a dynamically formatted JDBC theme. In the above code snippet, a JDBC theme was employed and the addInfoColumn() was used to add the info columns to be displayed by the info window.

A resolution value (e.g., "utfGridResolution":4) indicates the window width and height in the map tile image a grid cell represents. In this example, one grid cell in the UTFGrid dataset represents 16 pixels (4x4=16).

4) The dynamic tile layer makes use of Oracle Maps server JDBC themes when defining its map contents. In its embedded SQL statement, the client web application has the flexibility to construct the whole statement, including the tables to use, the columns to select and the "where" clause to refine the query. In the code snippets, it assumes that a client function, getWhereClauseFromUI(), is facilitated to only construct the 'where' clause in the JDBC theme definition.

Given the above description, you can see how the map application works. Its web user interface (UI) may allow a user to set value ranges for database columns of interest first. When a display event is invoked, then a dynamic tile layer's map is displayed. When the user clicks on a feature in the map, an info window pops-up, showing additional text attributes of the feature clicked. Because this layer is set transparently, it may have been just one of such dynamic tile layer instances with each dedicated for a spatial table (or each for a collection of different spatial tables). When the user changes some values from the UI, the existing dynamic tile layer instance is removed from the map application and a brand new dynamic tile layer is created and its map image tiles together with additional text attributes in the UTFGrid be fetched from the Oracle Maps server.

Note that if you prefer not to set a dynamic tile layer transparently, you may replace the 'transparent' property with a 'bgcolor' property with a background color value specified (see Oracle Maps user guide for details on background color specification).

A demo case

Screenshots from a demo application illustrate how dynamic tile layers can be used in a real application. This application maps three US weather-systems (wind, tornado, and hail) that caused damage to human lives, property, and agriculture from 1950 to 2010. Each category is represented by one dynamic tile layer, and each event is shown as a point at the event location in a color coded marker symbol. The needed marker symbols are pre-defined in Oracle Maps server metadata in view USER_SDO_STYLES. There are a little over 600,000 events in total for all three categories. This application's web UI allows an analyst to change the criteria for extracting a subset of the data to display.

Screenshot 1: Overall look and feel of the application

This map application contains four tile layers and their names are seen near the upper-left corner. The first layer is the background map. It is a regular tile layer and 'Oracle' (it indicates Oracle Maps eLocation map service) is selected in the screenshot to provide map images. The other three layers are all dynamic tile layers. They are for wind, tornado, and hail respectively to display their event locations, and the hail layer is the last layer on top of the display stack.

When the web application is initially accessed, all three dynamic tile layers are visible, and each one shows all of the data points (because no filter has been applied on the data yet, as it is designed in this application). At the initial map zoom level, the scalable marker symbols become a dot in the map, and some areas get data points that are so dense that the top layer covers the underneath layers. At this point, as an end user, you get the sense about how much data you have. You would filter the data and/or zoom in to small areas of interest for further inspection. Let's modify the data filtration criteria first.

Screenshot 2: Apply data filters to display a subset.

Screenshot 2 filtered the original data. The filters applied only extract events that had caused equal or more than one million-dollar property damage to be displayed. On the web UI, when you click on the arrow icon to the right of each dynamic tile layer, a pop-up window shows up to allow you to define the data filtering criteria. When you click the 'Apply filters' button in the pop-up window, actions will take place behind the scenes. There are two key actions: remove the existing dynamic tile layer from the map application, and then create a new dynamic tile layer to display new data extracted according to the modified data filtration criteria. You may now want to drill down to a small area of interest to examine the data more closely.

Screenshot 3: Zoom in to a small area of interest

In screenshot 3, the detailed background map and all three filtered dynamic tile layers are clearly seen: blue rectangle markers are for the wind damage event location, brown circles are for the tornados, and cyan colored diamonds are for hail. It is worth pointing out two properties of this application.

1) Because each dynamic tile layer is set to be transparent (see code snippet example 5), the background map tile layer (i.e., the first layer that gets map images from Oracle Maps eLocation) is visible, and marker symbols of other three dynamic tile layers are also visible while not covered by other layers, if any, above it.

2) If you click on an event marker symbol, the enabled UTFGrid feature allows this map application to pop-up an info window to show additional text attributes (note that code snippet example 5 has shown how the text attributes are specified).

When should I use a dynamic tile layer?

1) You should use a dynamic tile layer when you need to define a tile layer in your web application and it does not exist in Oracle Maps server metadata. In other words, a dynamic tile layer does not require a row in the Oracle Database in view USER_SDO_CASHED_MAPS to define its specifications. (For a regular tile layer, a tile layer must have been defined in Oracle Maps server metadata before being used in a client map application.)

2) When you need the flexibility of defining tile layers to fetch map images from different map resources from an Oracle Maps server, then you need to use a dynamic tile layer. It supports the following options:

a) Use a server basemap to provide map contents (see Example 1 for details) if the basemap has already been defined in metadata in view USER_SDO_MAPS.

b) Use a list of predefined themes (see Example 2 for details). The themes should have already been defined in metadata in view USER_SDO_THEMES.

c) Use spatial tables in an Oracle Database and construct server JDBC themes dynamically for map image rendering (see Examples 3 and 5 for details). It only needs the Oracle spatial tables for Oracle Maps server to render the requested image maps.

3) You need to use a dynamic tile layer when you need to fetch maps from a third party map service provider. In this case, you also need to define a URL generation function for the dynamic tile layer to fetch map images (see Example 4 for details).

Applications that a dynamic tile layer best fit

Because a dynamic tile layer is defined on the client side and does not depend on the server side definition (it does not need the server metadata in view USER_SDO_CACHED_MAPS to define it) and JDBC themes can be formulated according to a client side designed user interface, dynamic tile layer instances can be created dynamically according to some ad-hoc parameters in a UI setting. It best fits in applications where a user needs to view data from different perspectives. For example, in big data analytics and data mining, an analyst may need to apply different data filtration and segmentation techniques. A dynamic tile layer may be constructed as needed dynamically to display the data of interest on map images. In addition, when Oracle Maps server is used to provide map images, a data analyst does not need to be concerned about the server's storage space, because Oracle Maps server does not disk-cache dynamic tile layer's map images.

Many other features provided by Oracle Maps server, such as UTFGrid support, map image transparent setting, background color setting, and map layer visibility control will only enhance end user experiences for Oracle Maps based map applications.

Dynamic tile layer may also extend regular Oracle Maps mapping capabilities by its client side provided URL generation function option. This allows a map application to easily integrate map contents from different map service providers to enrich the map contents delivered to the end user.

Summary:

The dynamic tile layer type in Oracle Maps V2 API has eliminated many constraints from a regular tile layer and provides flexibility on how a dynamic tile layer is defined and where to fetch its map images.

When the map images are fetched from an Oracle Maps server, it does not require a tile layer to be defined in advance in server metadata, map images are freshly generated instead of using disk-cached images, and the map images are not disk-cached. When defining a dynamic tile layer, its map contents may come from a server basemap, a list of predefined themes, or dynamically formulated JDBC themes.

When the map images are fetched from a third party map service provider, a dynamic tile layer allows a web application to define its map image URLs, and thus map images may be fetched from any map service providers.

Dynamic tile layer feature is best suited for big data applications where visual analysis, as part of big data analytics, helps provide greater insight from that data.

Script to add missing metadata to mvdemo (12.2.1.1.0) schema for DTL examples

-- Note: if the quotes (single or double) are converted to smart-quotes on copy-n-paste then the 
-- script may have to be manually edited to fix that
-- execute the following SQL statements in sqlplus or SqlDeveloper as the mvdemo2 (or nedata) user
-- to add the required theme, map, and tile layers for the Dy Tile Layer examples
-- set define off is needed so that the ampersand in &gt; is not treated as a substitution variable
set define off;

insert into user_sdo_themes values ('UTFGRID_THEME_DEMO_CITIES', 'for utfgrid testing', 'CITIES_US', 'LOCATION',
'<?xml version="1.0" standalone="yes"?>
<styling_rules>
  <hidden_info>
    <field column="CITY" name="City"/>
    <field column="POP90" name="Population"/>
  </hidden_info>
  <rule>
    <features style="M.ALL_CITY_L2"> (pop90 between 200000 AND 1000000 ) </features>
    <label column="city" style="T.S07_CITIES_L2"> 1 </label>
  </rule>
  <rule>
    <features style="M.ALL_CITY_L3"> (pop90 between 0 and  200000) </features>
    <label column="city" style="T.S07_CITIES_L3"> 1 </label>
  </rule>
</styling_rules>') ;

insert into user_sdo_themes values ('UTFGRID_THEME_DEMO_COUNTIES', 'for utfgrid testing', 'COUNTIES', 'GEOM',
'<?xml version="1.0" standalone="yes"?>
<styling_rules>
  <hidden_info>
    <field column="COUNTY" name="County"/>
    <field column="POPPSQMI" name="PopulationDensity"/>
    <field column="TOTPOP" name="Population"/>
    <field column="STATE_ABRV" name="State"/>
  </hidden_info>
  <rule>
    <features style="L.S06_BORDER_STATE"> </features>
  </rule>
</styling_rules>') ;

insert into user_sdo_themes values ('UTFGRID_THEME_DEMO_STATES', 'for utfgrid testing', 'STATES', 'GEOM',
'<?xml version="1.0" standalone="yes"?>
<styling_rules>
  <hidden_info>
    <field column="STATE" name="State"/>
    <field column="STATE_ABRV" name="Abrv."/>
    <field column="TOTPOP" name="Population"/>
  </hidden_info>
  <rule>
    <features style="C.S02_COUNTRY_AREA"> </features>
    <label column="STATE_ABRV" style="T.S02_STATE_ABBREVS"> 1 </label>
  </rule>
</styling_rules>') ;

insert into user_sdo_themes values ('UTFGRID_THEME_DEMO_HIGHWAYS', 'for utfgrid testing', 'INTERSTATES', 'GEOM',
'<?xml version="1.0" standalone="yes"?>
<styling_rules>
  <hidden_info>
    <field column="HIGHWAY" name="Highway"/>
    <field column="ROUTEN" name="No."/>
  </hidden_info>
  <rule>
    <features style="L.S04_ROAD_INTERSTATE"> </features>
    <label column="routen" style="M.HWY_USA_INTERSTATE_NARROW"> (3-length(routen)) </label>
  </rule>
</styling_rules>') ;

insert into user_sdo_themes values ('THEME_US_DYN_HIGHWAYS', 'dynamic theme for utfgrid testing', 'INTERSTATES', 'GEOM',
'<?xml version="1.0" standalone="yes"?>
<styling_rules key_column="ROWID" caching="NORMAL">
  <hidden_info>
        <field column="HIGHWAY" name="Highway"/>
        <field column="ROUTEN" name="Number"/>
  </hidden_info>
  <rule>
    <features style="L.PH"> ROUTEN=:1 </features>
    <label column="HIGHWAY" style="T.AIRPORT NAME"> 1 </label>
  </rule>
</styling_rules>') ;

insert into user_sdo_themes values ('THEME_US_DYN_COUNTIES', 'dynamic theme for utfgrid testing', 'COUNTIES', 'GEOM',
'<?xml version="1.0" standalone="yes"?>
<styling_rules key_column="ROWID" caching="NORMAL">
  <rule>
    <features style="C.COUNTIES"> COUNTY=:1 </features>
    <label column="COUNTY" style="T.AIRPORT NAME"> 1 </label>
  </rule>
  <rule>
    <features style="C.RED"> TOTPOP&gt;:2 </features>
    <label column="COUNTY" style="T.PARK NAME"> 1 </label>
  </rule>
</styling_rules>') ;

insert into user_sdo_themes values ('THEME_US_DYN_STATES', 'dynamic theme for utfgrid testing', 'STATES', 'GEOM',
'<?xml version="1.0" standalone="yes"?>
<styling_rules key_column="ROWID" caching="NORMAL">
  <rule>
    <features style="C.RED"> state_abrv=:1 </features>
    <label column="STATE" style="T.PARK NAME"> 1 </label>
  </rule>
</styling_rules>') ;



insert into user_sdo_maps values ('COUNTY_UTFGRID_BASEMAP', null, 
'<?xml version="1.0" standalone="yes"?>
  <map_definition>
    <theme name="THEME_DEMO_COUNTY_POPDENSITY"/>
    <theme name="THEME_DEMO_STATES_LINE" label_min_scale="Infinity" label_max_scale="1.6E7" scale_mode="RATIO"/>
    <theme name="THEME_DEMO_HIGHWAYS_LINE"/>
    <theme name="THEME_DEMO_CITIES" min_scale="1.6E7" max_scale="0.0" scale_mode="RATIO"/>
  </map_definition>') ;
insert into user_sdo_maps values ('UTFGRID_BASEMAP', null, 
'<?xml version="1.0" standalone="yes"?> 
  <map_definition> 
    <theme name="UTFGRID_THEME_DEMO_STATES" min_scale="1.0e20" max_scale="0.0" scale_mode="RATIO"/>
    <theme name="UTFGRID_THEME_DEMO_HIGHWAYS" min_scale="1.0e20" max_scale="0.0" scale_mode="RATIO"/>
    <theme name="UTFGRID_THEME_DEMO_CITIES" min_scale="7.5e6" max_scale="0.0" scale_mode="RATIO"/>
</map_definition>') ;

insert into user_sdo_cached_maps values('UTFGRID_TL', null, null, 'YES', 'YES', 
'<?xml version = "1.0" encoding = "UTF-8"?>
<map_tile_layer concurrent_fetching_threads="3" fetch_larger_tiles="false" http_header_expires="168.0" image_format="PNG" name="UTFGRID_TL" utfgrid="true" utfgrid_resolution="4">
   <internal_map_source base_map="UTFGRID_BASEMAP" bgcolor="none" data_source="MVDEMO" db_tile_table=""/>
   <tile_storage root_path="/temp/MVDEMO.UTFGRID_TL/" xyz_storage_scheme="true"/>
   <coordinate_system maxX="180.0" maxY="90.0" minX="-180.0" minY="-90.0" srid="8307"/>
   <tile_image height="256" width="256"/>
   <tile_dpi value="90.7142857"/>
   <tile_meters_per_unit value="111319.49079327358"/>
   <zoom_levels levels="19" max_scale="5.590822640287178E8" min_scale="2132.729583849784" min_tile_height="360.0000000566929" min_tile_width="0.0013732910158412662">
      <zoom_level description="" level="0" name="" scale="5.590822640287178E8" tile_height="360.0000000566929" tile_width="360.0000000566929"/>
      <zoom_level description="" level="1" name="" scale="2.795411320143589E8" tile_height="180.00000002834645" tile_width="180.00000002834645"/>
      <zoom_level description="" level="2" name="" scale="1.3977056600717944E8" tile_height="90.00000001417322" tile_width="90.00000001417322"/>
      <zoom_level description="" level="3" name="" scale="6.988528300358972E7" tile_height="45.00000000708661" tile_width="45.00000000708661"/>
      <zoom_level description="" level="4" name="" scale="3.494264150179486E7" tile_height="22.500000003543306" tile_width="22.500000003543306"/>
      <zoom_level description="" level="5" name="" scale="1.747132075089743E7" tile_height="11.250000001771653" tile_width="11.250000001771653"/>
      <zoom_level description="" level="6" name="" scale="8735660.375448715" tile_height="5.6250000008858265" tile_width="5.6250000008858265"/>
      <zoom_level description="" level="7" name="" scale="4367830.1877243575" tile_height="2.8125000004429133" tile_width="2.8125000004429133"/>
      <zoom_level description="" level="8" name="" scale="2183915.0938621787" tile_height="1.4062500002214566" tile_width="1.4062500002214566"/>
      <zoom_level description="" level="9" name="" scale="1091957.5469310894" tile_height="0.7031250001107283" tile_width="0.7031250001107283"/>
      <zoom_level description="" level="10" name="" scale="545978.7734655447" tile_height="0.35156250005536416" tile_width="0.35156250005536416"/>
      <zoom_level description="" level="11" name="" scale="272989.38673277234" tile_height="0.17578125002768208" tile_width="0.17578125002768208"/>
      <zoom_level description="" level="12" name="" scale="136494.69336638617" tile_height="0.08789062501384104" tile_width="0.08789062501384104"/>
      <zoom_level description="" level="13" name="" scale="68247.34668319309" tile_height="0.04394531250692052" tile_width="0.04394531250692052"/>
      <zoom_level description="" level="14" name="" scale="34123.67334159654" tile_height="0.02197265625346026" tile_width="0.02197265625346026"/>
      <zoom_level description="" level="15" name="" scale="17061.83667079827" tile_height="0.01098632812673013" tile_width="0.01098632812673013"/>
      <zoom_level description="" level="16" name="" scale="8530.918335399136" tile_height="0.005493164063365065" tile_width="0.005493164063365065"/>
      <zoom_level description="" level="17" name="" scale="4265.459167699568" tile_height="0.0027465820316825325" tile_width="0.0027465820316825325"/>
      <zoom_level description="" level="18" name="" scale="2132.729583849784" tile_height="0.0013732910158412662" tile_width="0.0013732910158412662"/>
   </zoom_levels>
</map_tile_layer>', 'UTFGRID_BASEMAP', null);

insert into user_sdo_cached_maps values('COUNTY_UTFGRID_TL', null, null, 'YES', 'YES', 
'<?xml version = "1.0" encoding = "UTF-8"?>
<map_tile_layer concurrent_fetching_threads="3" fetch_larger_tiles="false" http_header_expires="168.0" image_format="PNG" name="COUNTY_UTFGRID_TL" utfgrid="true" utfgrid_resolution="4">
   <internal_map_source base_map="COUNTY_UTFGRID_BASEMAP" bgcolor="none" data_source="MVDEMO" db_tile_table=""/>
   <tile_storage root_path="/temp/MVDEMO.COUNTY_UTFGRID_TL/" xyz_storage_scheme="true"/>
   <coordinate_system maxX="180.0" maxY="90.0" minX="-180.0" minY="-90.0" srid="8307"/>
   <tile_image height="256" width="256"/>
   <tile_dpi value="90.7142857"/>
  <tile_meters_per_unit value="111319.49079327358"/>
   <zoom_levels levels="12" min_scale="858.0000000000007" max_scale="3.0289566E8" min_tile_width="5.220577239966284E-4" max_tile_width="184.2995557902756">
      <zoom_level level="0" name="level0" description="" scale="3.0289566E8" tile_width="184.2995557902756" tile_height="184.2995557902756"/>
      <zoom_level level="1" name="level1" description="" scale="9.483028858852641E7" tile_width="57.70033173248195" tile_height="57.70033173248195"/>
      <zoom_level level="2" name="level2" description="" scale="2.9689377635134164E7" tile_width="18.064765635285003" tile_height="18.064765635285003"/>
      <zoom_level level="3" name="level3" description="" scale="9295122.44960365" tile_width="5.655699848846204" tile_height="5.655699848846204"/>
      <zoom_level level="4" name="level4" description="" scale="2910108.2014895976" tile_width="1.770681193768741" tile_height="1.770681193768741"/>
      <zoom_level level="5" name="level5" description="" scale="911093.9409666553" tile_width="0.5543632041587065" tile_height="0.5543632041587065"/>
      <zoom_level level="6" name="level6" description="" scale="285244.43484309333" tile_width="0.17355951099870603" tile_height="0.17355951099870603"/>
      <zoom_level level="7" name="level7" description="" scale="89304.05960402885" tile_width="0.05433784860202624" tile_height="0.05433784860202624"/>
      <zoom_level level="8" name="level8" description="" scale="27959.231057906272" tile_width="0.017012042576674106" tile_height="0.017012042576674106"/>
      <zoom_level level="9" name="level9" description="" scale="8753.449785099405" tile_width="0.005326114302946117" tile_height="0.005326114302946117"/>
      <zoom_level level="10" name="level10" description="" scale="2740.521832720056" tile_width="0.001667494860784266" tile_height="0.001667494860784266"/>
      <zoom_level level="11" name="level11" description="" scale="858.0000000000007" tile_width="5.220577239966284E-4" tile_height="5.220577239966284E-4"/>
   </zoom_levels>
</map_tile_layer>', 'COUNTY_UTFGRID_BASEMAP', null);


update user_sdo_themes set styling_rules = 
'<?xml version="1.0" standalone="yes"?>
<styling_rules key_column="FIPSSTCO" fetch_size="500">
  <hidden_info>
    <field column="COUNTY" name="County"/>
    <field column="STATE_ABRV" name="State"/>
    <field column="POPPSQMI" name="Pop_per_sq_mile"/>
    <field column="TOTPOP" name="TotalPopulation"/>
  </hidden_info>
  <rule column="TOTPOP">
    <features asis="true" style="V.COUNTY_POP_DENSITY"> </features>
  </rule>
</styling_rules>'
where name = 'THEME_DEMO_COUNTY_POPDENSITY';


Sunday Dec 06, 2015

Using a container datasource in Tomcat with MapViewer 12.2.1

Using a container data source in MapViewer (12.2.1) deployed on  Tomcat requires a modification to the usual process of defining a JNDI resource in Tomcat. To get the container datasource to work with MapViewer you need to prefix the string "java:comp/env/" to the container_ds name in the <map_data_source> entry in mapViewerConfig.xml.

That is, your entry should look like:

  <map_data_source name="mvdemo_container_ds"
                   container_ds="java:comp/env/jdbc/mvdemo"
                   number_of_mappers="4"
                   allow_jdbc_theme_based_foi="false"
                   editable="false"
   />

Do this after following the standard steps for defining a JNDI resource in Tomcat which uses the Oracle JDBC driver. That is,

  • the Oracle jdbc driver related classes (e.g. ojdbc6-12.10.jar, ora18n-12.1.0.jar) should be in TOMCAT_HOME/lib
  • Add the resource description to MapViewer's context.xml, i.e. mapviewer_home/META-INF/context.xml should contain an entry similar to:
    <Resource name="jdbc/mvdemo"
               auth="Container"
               type="javax.sql.DataSource"
               driverClassName="oracle.jdbc.OracleDriver"
                url="jdbc:oracle:thin:@host:port:SID"
               username="mvdemo"
               password="pwd4mvdemo"
              validationQuery="SELECT 1 FROM DUAL"
              validationInterval="30000"
              timeBetweenEvictionRunsMillis="30000"
              maxActive="100"
              minIdle="10"
              maxIdle="100"
              maxWait="10000"
              initialSize="10"
              removeAbandonedTimeout="60"
              removeAbandoned="true"
              logAbandoned="true"
             accessToUnderlyingConnectionAllowed="true"
        />

     

  • Add the resource description to MapViewer's web/xml (mapviewer_home/WEB-INF/web.xml). It should be similar to:
    <resource-ref>
     <description>Oracle Datasource example</description>
     <res-ref-name>jdbc/mvdemo</res-ref-name>
     <res-type>oracle.jdbc.pool.OracleDataSource</res-type>
     <res-auth>Container</res-auth>
    </resource-ref>

Friday Dec 04, 2015

New feature type (MapMarker) in the recent release

The javascript lib (Oracle Maps) in the recent MapViewer release (12.2.1) has a new feature class called MapMarker. The primary purpose is to simplify the process of creating adding markers from a set of POI records, with labels such as 'A' - 'Z' or '1' - 'N' on them. It also supports dragging the markers around and handling the drag events. You can for instance drag the start and destination marker on a route to re-route it.

This post contains sample code showing how to do the latter, that is create draggable markers and handle the drag events.

The screenshot below shows the result.

Draggable markers example screenshot

The code is given below. The steps are create a map object, create one or more MapMarkers, set the dragStart and dragEnd listeners, add the markers to a MarkerLayer (a type of VectorLayer), display the map.

The MapMarker class has the following attributes and methods.

A constructor which takes a config object that defines the attributes and optionally the listeners.
OM.MapMarker(options)
where options is an object, or object literal, containing :

  • id {String}: The unique id for the map marker.
  • label {String}: The marker's label text.
  • draggable {Boolean}: Optional. The marker is draggable when this param is set to true.
  • renderingStyle {OM.style.Marker}: Optional. The rendering style for the marker. A default style will be used if none is specified.
  • position {Object}: The marker's position. It may contain the following attributes:
    • x {Number}: The marker's x coordinate
    • y {Number}: The marker's y coordinate
    • srid {Integer}: Optional. The coordinate system for the above x,y values. Default is 8307.
  • dragStart {Function}: Optional. The drag start event listener function.
  • dragging {Function}: Optional. The dragging event listener function.
  • dragEnd {Function}: Optional. The drag end event listener function.

And setters and getters for the above attributes. That is
setId(id)
getId()
setLabel(label)
getLabel()
setDraggable(draggable)
isDraggable()
setPosition(x,y,srid)
getPosition() which returns  an Object containing x, y, and srid
setStyle(sty)
getStyle(sty) which returns a marker style, i.e. an OM.style.Marker
setDragEndListener(dragEndListenerFunction)
setDragStartListener(dragStartListenerFunction)
setDraggingListener(draggngListenerFunction)

A marker layer (OM.layer.MarkerLayer)  is a vector layer than only contains MapMarkers.

The sample code is below. This assumes the 12.2.1 Glassfish based quickstart kit is deployed.

 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html style='width:100%;height:100%'>
<head>
<title>Draggable map markers</title>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<style>body{width:100%;height:100%;margin:0;padding:0}</style>
<script type='text/javascript' src='http://localhost:8080/mapviewer/jslib/v2/oraclemapsv2.js'></script>
<style type= 'text/css '>body {cursor:default;}</style>

<script language="JavaScript" type="text/javascript">
    var layer;
    var map;

    function showMap()
    {
        var baseURL = "http://localhost:8080/mapviewer";
        map = new OM.Map(
                document.getElementById('map'),
                {
                    mapviewerURL: baseURL
                });

        var tileLayer = new OM.layer.TileLayer(
                "baseMap",
                {
                    dataSource: "mvdemo",
                    tileLayer: "demo_map",
                    tileServerURL: baseURL + "/mcserver"
                });
        map.addLayer(tileLayer);
        layer = new OM.layer.MarkerLayer("markerlayer1");
        var dragStart = function(evt){
         document.getElementById("dragstart").innerHTML="Drag started from location (x, y): ("+
                                 evt.markerX.toFixed(4)+", "+evt.markerY.toFixed(4)+").";};
        var dragEnd = function(evt){
         document.getElementById("dragging").innerHTML="Dropped at location (x, y): ("
                                +evt.markerX.toFixed(4)+", "+evt.markerY.toFixed(4)+").";};
        var dragging = function(evt){
         document.getElementById("dragging").innerHTML="Dragging now at location (x, y): ("
                                +evt.markerX.toFixed(4)+", "+evt.markerY.toFixed(4)+").";};

        // Create an empty MapMarker and then set all properties. srid is the default (8307)
        var insertMapMarker1 = function(id, cx, cy, label, draggable) {
                var mm = new OM.MapMarker();
                layer.addMapMarker(mm);   // add a map marker into marker layer
                mm.setPosition(cx, cy);
                mm.setLabel(label);  // it will also set the marker text.
                mm.setID(id);
                mm.setDraggable(draggable);
                mm.setDragStartListener(dragStart);
                mm.setDragEndListener(dragEnd);
                mm.setDraggingListener(dragging);
        };

        // Specify properties in the options object. srid is the default (8307)
        var insertMapMarker2 = function(id, cx, cy, label, draggable) {
                var myobj = {'id': id,
                             'label': label,
                             'draggable': draggable,
                             'dragStart': dragStart,
                             'dragEnd': dragEnd,
                             'dragging': dragging,
                             'position': {'x': cx, 'y': cy}};
                var mm = new OM.MapMarker(myobj);
                layer.addMapMarker(mm);   // add a map marker into marker layer
        };

        // an obj with all properties to instantiate a map marker
        var insertMapMarker3 = function(id, cx, cy, srid, label, draggable) {
                var myobj = {'id': id,
                             'label': label,
                             'draggable': draggable,
                             'dragStart': dragStart,
                             'dragEnd': dragEnd,
                             'dragging': dragging,
                             'position': {'x': cx, 'y': cy, 'srid': srid}};
                var mm = new OM.MapMarker(myobj);
                var styleForNonDragableMarker = new OM.style.Marker({
            				src: "http://localhost:8080/mvdemo/icons/p_or_ena.png",
            				width: 50,  height: 50,
            				textStyle: {fontSize: 12, fill: '#000000'},
            				textOffset: {x: -2, y: -3}});
                if(!mm.isDraggable()) {
                    mm.setStyle(styleForNonDragableMarker);
                    console.log("Setting style for non-draggable marker " + mm.getLabel());
                }
                layer.addMapMarker(mm);   // add a map marker into marker layer
        };
        insertMapMarker1('m1', -122.3, 38.5, '11', true);  // id, cx, cy, srid, label, draggable
        insertMapMarker2('m2', -122, 37.5, '22', true);
        insertMapMarker3('m3', -120.7, 38, 8307, '33', true);
        insertMapMarker3('m4', -121, 39, 8307, ''); // m4 will not be draggable and should use a different style

        map.addLayer(layer);
        layer.setToolTipCustomizer(featureTip);

        map.setMapCenter(new OM.geometry.Point(-122, 38, 8307));
        map.setMapZoomLevel(5);
        var copyRight=new OM.control.CopyRight({anchorPosition:6,textValue:'Map data@NaturalEarth',fontSize:8,fontFamily:'Arial',fontColor:'black'});
        map.addMapDecoration(copyRight);
        addMouseEventListener();
        map.init();
    }
    function addMouseEventListener(){
        map.addListener(OM.event.MouseEvent.MOUSE_MOVE, featureMouseMove);
        layer.enableInfoWindow(false);
    }
    function featureMouseMove()
    {
        var mouseLoc = map.getCursorLocation();
        var x = mouseLoc.getX();
        var y = mouseLoc.getY();
        document.getElementById("mouseLocation").innerHTML="Mouse location (x, y): ("
                                +x.toFixed(4)+", "+y.toFixed(4)+").";
    }
    function featureTip(f)
    {
        return "id: "+f.id+"\nlabel: "+ (f.label ? f.label : 'undefined');
    }

</script>

</head>
<body onload="javascript:showMap()">
    <DIV id=map style="width:90%;height:90%;margin:10px;"></DIV>
    <span id="text">Creating draggable map markers.</span>   
    <span id="mouseLocation"></span><br/>
    <span id="dragstart"></span> 
    <span id="dragging"></span>
</body>
</html>


Tuesday Nov 10, 2015

Note on deploying generic 12.2 ear on non-WLS JEE servers

The MapViewer console pages require logging in as a user with the map_admin_role role. Here is an example of creating that role and a user with that role on Tomcat 8.

Modify the tomcat-users.xml file in the conf directory to add the map_admin_role and a user with that role. This is needed for the MapViewer console login.
e.g.
  <role rolename="manager-gui"/>
  <role rolename="admin"/>
  <role rolename="admin-gui"/>
  <role rolename="manager-script"/>
  <role rolename="manager-status"/>
  <role rolename="map_admin_role"/>
  <user username="tomcat" password="s3cret" roles="map_admin_role,manager-gui,manager-script,admin-gui,admin"/>
  <user username="mv_admin" password="secr3t2" roles="manager-gui,admin,manager-script,manager-status, admin-gui,map_admin_role"/>

Tuesday Nov 03, 2015

MapViewer 12cR2 (12.2.1) released. Available on OTN

MapViewer 12.2.1 is now available for download from OTN at http://www.oracle.com/technetwork/middleware/mapviewer/downloads/index.html
This version includes a generic EAR file which can be deployed to other JEE containers such as Tomcat or GlassFish.  The WebLogic specific EAR requires WLS with JRF.

All MapViewer functionality is included in this kit, including the latest V2 JavaScript Mapping API.
[Read More]

Friday Nov 08, 2013

Latest MapViewer 11g patch released

Hi,

  We are glad to announce that the latest MapViewer 11g patch (version 11.1.1.7.2) has just been uploaded to OTN in the usual place. This is mostly a bug fix release, with several noticeable enhancements to the HTML5 API. For the full release note, please check it here:

 http://download.oracle.com/otndocs/products/mapviewer/mapviewer_11p6_2_readme.txt

In a related note, our hosted mapping service (elocation.oracle.com) has also updated its MapViewer server to this release.

Finally, the public demo server running all the standard mapViewer demos have been patched to 11.1.1.7.2 as well. So make sure to give the demos a spin!

http://slc02okf.oracle.com    :  show cases some of the main HTML5 mapping demos

http://slc02okf.oracle.com/mvdemo : the MapViewer Samples & Demos Application.

 Thanks

LJ 

Monday Oct 14, 2013

Updating the mapviewer in the quickstart kit

More than two (:-)) folks asked this question recently so it might worth a short note. The question is how does one deploy a new mapviewer version (e.g. 11.1.1.7.1) into the quickstart kit (which has 11.1.1.7.0)? A manual process is the simplest.

Shutdown the glassfish server if it's running.

Make a copy of the existing mapviewer.war directory and rename it (e.g. mapviewer.war.111170).

Delete the contents of the mapviewer.war directory (or create one named mapviewer.war if you just renamed, without copying, the old one).

Extract the contents of web.war in the new mapviewer.ear into the mapviewer.war directory.

Modify the mapviewerconfig.xml file so that it has the same map_data_source and other entries as the original one had.

If you're replacing 11.1.1.7.0 with 11.1.1.7.1 then you also have to edit the mds.xml (same location as mapviewerconfig.xml) to allow for the streaming of predefined and dynamic themes to the html5 client by the map data serevr. This change (data server streaming disabled by default) is new in 11.1.1.7.1.

Restart glassfish.

Monday Sep 02, 2013

A note on tile names and directory structure

This is a guest post by Honglei Zhu. 

Important: The tiling scheme described here can, and likely will, change and hence be invalid in future releases.

This note outlines the tile storage, and file naming conventions, for map tile layers created with FMW MapViewer. The tiles are stored in a directory structure based on the data source name, map tile layer name, number of zoom levels, and tile mesh codes.

Tile Mesh Code and File Storage Structure

Each map tile layer is in a directory under $DEFAULT_TILE_STORAGE_ROOT and named [datasource.tile_layer_name]. For example, if the default tile storage is /private/tilestore and the tile layer demo_map is in the datasource is mvdemo, then the tiles will be under /private/tilestore/MVDEMO.DEMO_MAP. The first level of subdirectories contains one directory per zoom level. So if there are 19 zoom levels then the subdirectories will be named 0 through 18. Each zoom level directory will contain tile (files) or directories. That is, tiles are stored in a tree-like directory structure with leaf nodes contain only tile image files. Non-leaf nodes contain only directories. Mesh codes are used in naming these subdirectories and tiles.

Tile Mesh Code

A tile mesh code is represented by X (horizontal) and Y (vertical) integer arrays, in a form of [meshX0, meshX1, meshX2, … meshXn] and [meshY0, meshY1, meshY2, … meshYn]. At each zoom level, the length for the X and Y mesh code array is always the same. Different zoom levels, however, may have different length arrays. The longer the mesh code, the more tile images that zoom level contains.

For a tile with mesh code of [meshX0, meshX1, meshX2, … meshXn] and [meshY0, meshY1, meshY2, … meshYn], its filename and path is: $DEFAULT_TILE_STORAGE_ROOT/[tile_layer_name]/[zoom_level]/[meshX0]_[meshY0]/ [meshX1]_[meshY1]/ [meshX2]_[meshY2]/…/ [meshXn]_[meshYn].png.

For example, a MVDEMO.DEMO_MAP tile at zoom level 10, with an X mesh code of [1, 12, 11] and a Y mesh code of [3, 12, 9] will be at: /private/tilestore/MVDEMO.DEMO_MAP/10/1_3/12_12/11_9.png

Note:Tile mesh codes are internal to MapViewer and are may change between releases. So the following description of how mesh codes are generated may not be valid in future releases.

The mesh code is computed from a tile index. The tile index (X,Y) is computed in the Oracle maps client code from the map tile layer definition as follows:

tileIndexX = (tileMinX–CoordinateSystem.minX) / tileWidth;

tileIndexY = (tileMinY–CoordinateSystem.minY) / tileHeight;

The server then converts the tile index to a mesh code.

Directory Tree Depth (Mesh Code Length)

When the number of tile images is small for a given zoom level, all tiles may be stored in its root directory. When the number gets to millions or even larger, at higher zoom levels, they are stored in subdirectories for more efficient file retrieval.

The expected number of tiles for a given zoom level is calculated using:

maxMeshCodeX = coordinateSystem.width/tileWidth;

maxMeshCodeY = coordinateSystem.height/tileHeight;

total_tiles = maxMeshCodeX*maxMeshCodeY;

A TILING_FACTOR determines the depth of the directory tree for a given zoom level. The default value of 20 means there will be no more than 400 (20 x 20) sub-directories or tile images stored at any zoom level. The mesh code length for X equals the base-20 (or base TILING_FACTOR) logarithm of maxMeshCodeX.

Examples of converting a tile index (x,y) to Mesh Code

1) Given that the TILING_FACTOR is 20, then for zoom level 6, the mesh code length is 4. If the tile index (x,y)=(6063, 7403), then its mesh code is x=[0,15,3,3], y=[0,18,10,3], and the tile is stored at:[tile_layer_name]\6\0_0\15_18\3_10\3_3.png

2) If the TILING_FACTOR is changed to 10, the mesh code length becomes 5. Keeping the zoom level and tile index the same, the mesh code is x=[0, 6, 0, 6, 3], y=[0,7,4,0,3], and the tile is stored at: [tile_layer_name]\6\0_0\6_7\0_4\6_0\3_3.png

Wednesday Aug 28, 2013

Potential memory usage issue when using the new MVDEMO data set

Just want to let people know that there is a memory usage issue when viewing the new MVDEMO data set at very detailed zoom levels.  As you probably have seen already the tile layer named 'demo_map' contains a raster layer that looks like the below screenshot:

mvdemo screenshot

The issue is that the base map 'demo_map' does not stop the display of this raster layer even for map scales that are way beyond the intrinsic resolution of the original raster. As a result, if you zoom in far enough, such as at zoom level 15 or beyond, the Java JAI library used for handling the raster image will cause OutOfMemory errors in the JVM and make MapViewer unresponsive. 

There is a very simple fix that involves running the following SQL statement in the database schema where the new MVDEMO data was imported:

[code] 

update user_sdo_maps
set definition=
'<?xml version="1.0" standalone="yes"?>
  <map_definition>
    <theme name="WORLD_RASTER" min_scale="1.5E18" max_scale="1000000.0" scale_mode="RATIO"/>
    <theme name="THEME_DEMO_STATES" min_scale="1.5E8" max_scale="0.0" scale_mode="RATIO"/>
    <theme name="THEME_DEMO_COUNTIES" min_scale="8500000.0" max_scale="0.0" scale_mode="RATIO"/>
    <theme name="THEME_DEMO_HIGHWAYS_LINE" min_scale="1.0E8" max_scale="4.5E7" scale_mode="RATIO"/>
    <theme name="THEME_DEMO_HIGHWAYS" min_scale="4.5E7" max_scale="0.0" scale_mode="RATIO"/>
    <theme name="THEME_DEMO_BIGCITIES" min_scale="4.5E7" max_scale="7500001.0" scale_mode="RATIO"/>
    <theme name="THEME_DEMO_CITIES" min_scale="7500000.0" max_scale="0.0" scale_mode="RATIO"/>
  </map_definition>'
  where name='DEMO_MAP';

commit; /

 [code]

 The above SQL changes the max_scale value for the raster layer in the basemap 'demo_map' (which the tile layer with the same name is based on).  Note that the other tile layer, 'world_map' already has the correct max_scale value for the raster theme. 

Remember to restart MapViewer or flush its cached metadata to pick up this new definition.

Thanks

LJ 

Tuesday Aug 20, 2013

Basic example of using GDAL/OGR with MapViewer

This is a quick example of using gdal/ogr to access 3rd party spatial data formats in MapViewer. Specifically a MapInfo mid/mif and TAB files using the builtin ogrSDP (ogr spatial data provider class) to define and access a custom geometry theme.

First, download and install GDAL. I used the prebuilt binaries for version 1.9.2 for 64-bit Windows.

The precompiled supported formats list includes ESRI and MapInfo files
C:\Program Files\GDAL>ogrinfo --formats
Supported Formats:
  -> "ESRI Shapefile" (read/write)
  -> "MapInfo File" (read/write)
...

Then copy the gdal.jar file in the GDAL/Java directory over to someplace where it is in the classpath for MapViewer and MapBuilder. I copied it to the WEB-INF/lib directory for MapViewer and the directory which has MapBuilder.

Start up MapBuilder with gdal in the classpath and define custom geometry themes, i.e. use something like the following command to start it.
java -Xmx512M -cp .\mapbuilder.jar;.\gdal.jar oracle.mapviewer.builder.MapBuilder

Then define Custom Geometry Theme(s) using the ogrSDP. The following screenshots show the definition of a VICTORIA_TAB (tab file format) and MAPINFO_EXAMPLE (mid/mif format)  of postcode boundaries for someplace in Victoria, AU in the VicGrid94 spatial reference system. The corresponding SDO srid is 82473.

Once these are defined they can used as predefined themes in MapViewer. This assumes the files are accessible by the MapViewer server and the gdal.jar file is in the lib directory or in the classpath for that MapViewer server.

To test it, I modified the C00 - Display a predefined vector layer sample to use a different tile and vector layer. That is, the following lines of the sample code were changed to use the MAPINFO_EXAMPLE theme instead of "customers"
        var tileLayer = new OM.layer.TileLayer(
        "baseMap",
        {
            dataSource:"mvdemo",
            tileLayer:"elocation_map",
            tileServerURL: baseURL+"/mcserver"
        });
        map.addLayer(tileLayer) ;
        layer = new OM.layer.VectorLayer("layer1",
        {
            def:{
                type:OM.layer.VectorLayer.TYPE_PREDEFINED,
                dataSource:"mvdemo2", theme:"MAPINFO_EXAMPLE",
                url: baseURL
            }
        }); 
Re-running the modified sample gives the result shown in the screenshot below.







Friday Jul 26, 2013

A note on using Spherical Mercator (epsg:3785) with 11g

This is a brief note on how to use Web Mercator (EPSG:3785) with database 11g and MapViewer.
Further details can be found in the Spatial and MapViewer documentation that is in
http://docs.oracle.com/cd/E16655_01/appdev.121/e17896/sdo_cs_concepts.htm#CIHJFBFG (Spatial), and
http://docs.oracle.com/cd/E28280_01/web.1111/e10145/vis_omaps.htm#BACDBCBI (MapViewer).

There are two options for using Web Mercator with MapViewer.

The first (and preferred option) is to use database version 11.2.0.3 (or later) and MapViewer 11.1.1.6 (or later) and use the ESPG:3857 srid instead. In order to do this the tile layer config definitions for the Google/Bing/OSM/Nokia etc. tile layers must be updated to change the SRID from 3785 to 3857.

If a database entry in user_sdo_cached_maps is used to specify the tile layer (and its config) then just update the stored definition in that view. For example, if the entry is
SQL> select name, definition from user_sdo_cached_maps where name='NOKIA_MAP';

NAME
--------------------------------
DEFINITION
--------------------------------------------------------------------------------
NOKIA_MAP
<map_tile_layer name="nokia_map">
   <external_map_source url="" builtin_tile_layer="nokia">
      <properties>
         <property name="lib_url" value="http://api.maps.nokia.com/2.2.0/jsl.js"/>
         <property name="key" value="your_api_key"/>
         <property name="appId" value="your_appId"/>
         <property name="map_type_values"
         value="MVNokiaTileLayer.TYPE_NORMAL;MVNokiaTileLayer.TYPE_SATELLITE;MVNokiaTileLayer.TYPE_TERRAIN"/>
         <property name="map_type_names" value="Normal;Satellite;Terrain"/>
         <property name="default_map_type" value="MVNokiaTileLayer.TYPE_NORMAL"/>
      </properties>
   </external_map_source>
   <coordinate_system srid="3785" minX="-2.0037508E7" minY="-2.0037508E7" maxX="2.0037508E7" maxY="2.0037508E7"/>
   <tile_image width="256" height="256"/>
   <zoom_levels levels="19" min_scale="0.0" max_scale="0.0" min_tile_width="76.43702697753906" min_tile_height="2.0037508E7">
      <zoom_level level="0" name="" description="" scale="0.0" tile_width="2.0037508E7" tile_height="2.0037508E7"/>
      <zoom_level level="1" name="" description="" scale="0.0" tile_width="1.0018754E7" tile_height="1.0018754E7"/>
      <zoom_level level="2" name="" description="" scale="0.0" tile_width="5009377.0" tile_height="5009377.0"/>
      <zoom_level level="3" name="" description="" scale="0.0" tile_width="2504688.5" tile_height="2504688.5"/>
      <zoom_level level="4" name="" description="" scale="0.0" tile_width="1252344.25" tile_height="1252344.25"/>
      <zoom_level level="5" name="" description="" scale="0.0" tile_width="626172.125" tile_height="626172.125"/>
      <zoom_level level="6" name="" description="" scale="0.0" tile_width="313086.0625" tile_height="313086.0625"/>
      <zoom_level level="7" name="" description="" scale="0.0" tile_width="156543.03125" tile_height="156543.03125"/>
      <zoom_level level="8" name="" description="" scale="0.0" tile_width="78271.515625" tile_height="78271.515625"/>
      <zoom_level level="9" name="" description="" scale="0.0" tile_width="39135.7578125" tile_height="39135.7578125"/>
      <zoom_level level="10" name="" description="" scale="0.0" tile_width="19567.87890625" tile_height="19567.87890625"/>
      <zoom_level level="11" name="" description="" scale="0.0" tile_width="9783.939453125" tile_height="9783.939453125"/>
      <zoom_level level="12" name="" description="" scale="0.0" tile_width="4891.9697265625" tile_height="4891.9697265625"/>
      <zoom_level level="13" name="" description="" scale="0.0" tile_width="2445.98486328125" tile_height="2445.98486328125"/>
      <zoom_level level="14" name="" description="" scale="0.0" tile_width="1222.992431640625" tile_height="1222.992431640625"/>
      <zoom_level level="15" name="" description="" scale="0.0" tile_width="611.4962158203125" tile_height="611.4962158203125"/>
      <zoom_level level="16" name="" description="" scale="0.0" tile_width="305.74810791015625" tile_height="305.74810791015625"/>
      <zoom_level level="17" name="" description="" scale="0.0" tile_width="152.87405395507812" tile_height="152.87405395507812"/>
      <zoom_level level="18" name="" description="" scale="0.0" tile_width="76.43702697753906" tile_height="76.43702697753906"/>
   </zoom_levels>
</map_tile_layer>

where the srid="3785" then update it using a SQL statement like
update user_sdo_cached_maps set definition = replace(definition, 'srid="3785"', 'srid="3857"')
where name='NOKIA_MAP';

If however the usage is via the OracleMaps API methods MVGoogleTileLayer or MVNokiaTileLayer etc. then set the srid to 3857 using their setSrid() method, e.g. myTileLayer.setSrid(3857);

The second (and not preferred) option is to add transformation rules that assume a sphere, instead of an ellipsoid, when transforming from the source srid to 3785. So, for example, when transforming from 4326 (WGS84) to 3785 assume that the ellipsoid (WGS 84) is just a sphere. That is not really the case, however, as shown by the query below.

SQL> select srid, datum_name, ellipsoid_name, semi_major_axis, semi_minor_axis from
  2  sdo_coord_ref_sys c, sdo_datums d, sdo_ellipsoids e where
  3  c.srid in (4326, 3785) and
  4  (c.datum_id=d.datum_id or c.geog_crs_datum_id=d.datum_id) and
  5   d.ellipsoid_id = e.ellipsoid_id ;

      SRID DATUM_NAME                       ELLIPSOID_NAME
---------- -------------------------------- -----------------------------
SEMI_MAJOR_AXIS SEMI_MINOR_AXIS
--------------- ---------------
      3785 Popular Visualisation Datum      Popular Visualisation Sphere
        6378137

      4326 World Geodetic System 1984       WGS 84
        6378137      6356752.31

SQL>

So the transformation rule says ignore that WGS84 is an ellipse and assume it's a sphere of radius 6378137 meters.

The rule is specified by the following SQL statement (which must be executed by a SYS or similarly privileged user.
-- For 4326, EPSG equivalent of 8307
call sdo_cs.create_pref_concatenated_op( 43263785, 'CONCATENATED_OPERATION_4326_3785', TFM_PLAN(SDO_TFM_CHAIN(4326, 1000000000, 4055, 19847, 3785)), NULL);
which says use the null operation (coord op id 1000000000) when transforming from the geodetic cs 4326 to the geodetic cs 4055, and thereby assume they are spheres of the same radius, and then use the spherical Mercator projection (coord op id 19847) to go to 3785.

SQL> select coord_op_name, coord_op_id from sdo_coord_ops where
  2  coord_op_id in (1000000000, 19847) ;

COORD_OP_NAME                     COORD_OP_ID
--------------------------------- -----------
Popular Visualisation Mercator    19847

EPSG No-Op (EPSG OP 1000000000)   1000000000

Each source SRID (e.g. Texas North, or North Carolina) will need its own TFM_CHAIN to go from the projected source srid to its geodetic srid to 4055 and then to 3785 while using a No-Op when going from its datum to 4055.

How are values/entries for these tfm_chain determined? Let's look at the two mentioned above (Texas North and NC).
We can query cs_srs to find that srid for these are 2844 and 32119.
Now query the sdo_coord_ref_sys table to find the crs_datum and projection_conv_id (i.e. coord_op_id) for them.
SQL> select coord_ref_sys_name, geog_crs_datum_id, source_geog_srid, projection_
conv_id from
  2  sdo_coord_ref_sys where srid in (2844, 32119) ;

COORD_REF_SYS_NAME             GEOG_CRS_DATUM_ID SOURCE_GEOG_SRID
------------------------------ ----------------- ----------------
PROJECTION_CONV_ID
------------------
NAD83(HARN) / Texas North                   6152             4152
             14231

NAD83 / North Carolina                      6269             4269
             13230

SQL>

Next query the datums and ellipsoids tables to check the semi-major axis radius for them.
SQL> select datum_name, ellipsoid_name, semi_major_axis from
  2  sdo_datums d, sdo_ellipsoids e where  d.datum_id in (6269, 6152) and
  3  d.ellipsoid_id=e.ellipsoid_id;

DATUM_NAME                       ELLIPSOID_NAME
-------------------------------- --------------------------------
SEMI_MAJOR_AXIS
---------------
NAD83 (High Accuracy Regional Ne GRS 1980
twork)
        6378137

North American Datum 1983        GRS 1980
        6378137

They both use GRS 1980 with a semi-major radius of 6378137 which is the radius for the spheroid for 4055 too so a No-Op can be used. So the tfm chain becomes
2844, -14231, 4152, 1000000000, 4055, 19847, 3785 for Texas North and
32119, -13230, 4269, 1000000000, 4055, 19847, 3785 for North Carolina.

The negative values of PROJECTION_CONV_ID are used since they are the inverse of the projection. That is, projection_conv_id is the operation to go from 4152 to 2844 or from 4269 to 32119.
SQL> select coord_op_name, coord_op_id from sdo_coord_ops where
  2  coord_op_id in (14231, 13230) ;

COORD_OP_NAME
-------------------------------------------------------------------------

COORD_OP_ID
-----------
SPCS83 North Carolina zone (meters) (EPSG OP 13230)
      13230

SPCS83 Texas North zone (meters) (EPSG OP 14231)
      14231

When a preferred tranformation rule, or operation, is defined it is added to the
sdo_preferred_op_system table.
SQL> desc sdo_preferred_ops_system
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------

 SOURCE_SRID                               NOT NULL NUMBER(10)
 COORD_OP_ID                               NOT NULL NUMBER(10)
 TARGET_SRID                               NOT NULL NUMBER(10)

 Now let's look at the coordinate conversions without any preferred (or custom) transformation rules.
 SQL> select count(1) from sdo_preferred_ops_system ;

  COUNT(1)
----------
         0
SQL> select city,
  2  sdo_cs.transform(location, 3857) loc_3857,
  3  sdo_cs.transform(sdo_cs.transform(location, 2844), 3857) loc_2844_3857,
  4  sdo_cs.transform(sdo_cs.transform(location, 2844), 3785) loc_2844_3785
  5  from cities where state_abrv='TX' and city='Amarillo' ;

CITY
------------------------------------------
LOC_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
--------------------------------------------------------------------------------
LOC_2844_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
LOC_2844_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
Amarillo
SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-11334404, 4191441.06, NULL), NULL, NULL)
SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-11334404, 4191441.06, NULL), NULL, NULL)
SDO_GEOMETRY(2001, 3785, SDO_POINT_TYPE(-11334404, 4166799.81, NULL), NULL, NULL)
The first two (using srid 3857) match up while the conversion to 3785 gives a different result which is slightly offset in Y.

Ditto for Raleigh, NC
SQL> select city,
  2  sdo_cs.transform(location, 3857) loc_3857,
  3  sdo_cs.transform(sdo_cs.transform(location, 32119), 3857) loc_32119_3857,
  4  sdo_cs.transform(sdo_cs.transform(location, 32119), 3785) loc_32119_3785
  5  from cities where state_abrv='NC' and city='Raleigh' ;

CITY
------------------------------------------
LOC_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
--------------------------------------------------------------------------------
LOC_2844_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
LOC_2844_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
Raleigh
SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-8756252.3, 4276149.54, NULL), NULL, NULL)
SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-8756252.3, 4276149.54, NULL), NULL, NULL)
SDO_GEOMETRY(2001, 3785, SDO_POINT_TYPE(-8756252.3, 4251131.29, NULL), NULL, NULL)

Now let's add the tfm rules.
 SQL> conn system@sdolnx2
Enter password:
Connected.
SQL> CALL sdo_cs.create_pref_concatenated_op(
  2    28443785,
  3    'CONCATENATED OPERATION',
  4    TFM_PLAN(SDO_TFM_CHAIN(2844, -14231, 4152, 1000000000, 4055, 19847, 3785)
),  NULL);

Call completed.
-- Give a different id and name to the next concatenated op
SQL> CALL sdo_cs.create_pref_concatenated_op(
  2    321193785,
  3    'CONCATENATED OPERATION 32119 3785',
  4    TFM_PLAN(SDO_TFM_CHAIN(32119, -13230, 4269, 1000000000, 4055, 19847, 3785)),  NULL);

Call completed.

Check that these were added
SQL> conn mvdemo@sdolnx2
Enter password:
Connected.
SQL> select * from sdo_preferred_ops_system;

SOURCE_SRID COORD_OP_ID TARGET_SRID
----------- ----------- -----------
       2844    28443785        3785
       3785   -28443785        2844
      32119   321193785        3785
       3785  -321193785       32119

Now try the above transform queries again and note that all three are the same.
SQL> select city,
  2  sdo_cs.transform(location, 3857) loc_3857,
  3  sdo_cs.transform(sdo_cs.transform(location, 2844), 3857) loc_2844_3857,
  4  sdo_cs.transform(sdo_cs.transform(location, 2844), 3785) loc_2844_3785
  5  from cities where state_abrv='TX' and city='Amarillo' ;

CITY
------------------------------------------
LOC_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
--------------------------------------------------------------------------------
LOC_2844_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
LOC_2844_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
Amarillo
SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-11334404, 4191441.06, NULL), NULL, NULL)
SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-11334404, 4191441.06, NULL), NULL, NULL)
SDO_GEOMETRY(2001, 3785, SDO_POINT_TYPE(-11334404, 4191441.06, NULL), NULL, NULL)      

SQL> select city,
  2  sdo_cs.transform(location, 3857) loc_3857,
  3  sdo_cs.transform(sdo_cs.transform(location, 32119), 3857) loc_32119_3857,
  4  sdo_cs.transform(sdo_cs.transform(location, 32119), 3785) loc_32119_3785
  5  from cities where state_abrv='NC' and city='Raleigh' ;

CITY
------------------------------------------
LOC_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
--------------------------------------------------------------------------------
LOC_32119_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDIN
--------------------------------------------------------------------------------
LOC_32119_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDIN
--------------------------------------------------------------------------------
Raleigh
SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-8756252.3, 4276149.54, NULL), NULL, NULL)
SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-8756252.3, 4276149.54, NULL), NULL, NULL)
SDO_GEOMETRY(2001, 3785, SDO_POINT_TYPE(-8756252.3, 4276149.54, NULL), NULL, NULL)

Lastly if the ellipsoid for the source projected system does not have the same semi-major axis value
(e.g for srid 27700, British National Grid) then the chain should be source to 4326 and then to 3785.
For BNG (srid 27700) the ellipsoid is Airy 1830 and the semi-major axis is 6377563.4.
SQL> select e.ellipsoid_name, e.semi_major_axis from sdo_ellipsoids e,
  2  sdo_datums d, sdo_coord_ref_sys c where
  3  c.srid=27700 and
  4  c.geog_crs_datum_id = d.datum_id and
  5  d.ellipsoid_id = e.ellipsoid_id ;

ELLIPSOID_NAME                        SEMI_MAJOR_AXIS
----------------------------------------   ---------------
Airy 1830                                    6377563.4


Add the rule for 4326 to 3785 and then test the direct to 3785 and via 4326 route transforms.
call sdo_cs.create_pref_concatenated_op(43263785, 'CONCATENATED_OPERATION_4326', TFM_PLAN(SDO_TFM_CHAIN(4326, 1000000000, 4055, 19847, 3785)), NULL);

First without adding a 27700 to 3785 tfm rule that does not go through 4326
SQL> select name, sdo_cs.transform(geometry, 27700) geom_bng,
  2  sdo_cs.transform(sdo_cs.transform(geometry, 27700), 3785) geom_bng_3785,
  3  sdo_cs.transform(sdo_cs.transform(sdo_cs.transform(geometry, 27700),4326),3
785) geom_bng_4326_3785
  4  from cities where iso_a2='UK' and name='London';

NAME
------------------------------
GEOM_BNG(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
--------------------------------------------------------------------------------
GEOM_BNG_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
GEOM_BNG_4326_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_O
--------------------------------------------------------------------------------
London
SDO_GEOMETRY(3001, 27700, SDO_POINT_TYPE(530678.086, 179789.242, 0), NULL, NULL)
SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6677081.27, 0), NULL, NULL)
SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6710566.11, 0), NULL, NULL)

Next add one for 27700 which is likely incorrect
call sdo_cs.create_pref_concatenated_op(277003785, 'CONCATENATED_OPERATION_27700', TFM_PLAN(SDO_TFM_CHAIN(27700, -19916, 4277, 1000000000, 4055, 19847, 3785)), NULL);

select name, sdo_cs.transform(geometry, 27700) geom_bng,
sdo_cs.transform(sdo_cs.transform(geometry, 27700), 3785) geom_bng_3785,
sdo_cs.transform(sdo_cs.transform(sdo_cs.transform(geometry, 27700),4326),3785) geom_bng_4326_3785,
sdo_cs.transform(sdo_cs.transform(geometry, 27700), 3857) geom_bng_3857
from cities where iso_a2='UK' and name='London';

NAME
------------------------------
GEOM_BNG(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
--------------------------------------------------------------------------------
GEOM_BNG_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
GEOM_BNG_4326_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_O
--------------------------------------------------------------------------------
GEOM_BNG_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
London
SDO_GEOMETRY(3001, 27700, SDO_POINT_TYPE(530678.086, 179789.242, 0), NULL, NULL)
SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13031.112, 6710474.7, 0), NULL, NULL)
SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6710566.11, 0), NULL, NULL)
SDO_GEOMETRY(3001, 3857, SDO_POINT_TYPE(-13210.033, 6710566.11, 0), NULL, NULL)

The 3rd and 4th agree. The second (which is 27700 -> 3785 with the rule) disagrees with both
the 27700 -> 3857 and the 27700 -> 3785 without a rule.
Without a rule it is:
SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6677081.27, 0), NULL, NULL)
With a rule that does not iclude 4326 in the chain it is:
SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13031.112, 6710474.7, 0), NULL, NULL)

Now modify the rule to correct the chain to include 4326
SQL> call sdo_cs.delete_op(277003785);

Call completed.
SQL> select coord_op_id, coord_op_name, target_srid from sdo_coord_ops where source_srid=4277 ;
COORD_OP_ID COORD_OP_NAME                                      TARGET_SRID
----------- -------------------------------------------------- -----------
       1195 OSGB 1936 to WGS 84 (1) (EPSG OP 1195)                    4326
       1196 OSGB 1936 to WGS 84 (2) (EPSG OP 1196)                    4326
       1197 OSGB 1936 to WGS 84 (3) (EPSG OP 1197)                    4326
       1198 OSGB 1936 to WGS 84 (4) (EPSG OP 1198)                    4326
       1199 OSGB 1936 to WGS 84 (5) (EPSG OP 1199)                    4326
       1314 OSGB 1936 to WGS 84 (Petroleum) (EPSG OP 1314)            4326
       1315 OSGB 1936 to ED50 (UKOOA) (EPSG OP 1315)                  4230

7 rows selected.

We'll use coord_op_id 1195

call sdo_cs.create_pref_concatenated_op(
277003785, 'CONCATENATED_OPERATION_27700', TFM_PLAN(
SDO_TFM_CHAIN(27700, -19916, 4277, 1195, 4326, 1000000000, 4055, 19847, 3785)), NULL);

Redo the query for London to see the if the direct, via 4326, and to 3857 all agree.

select name, sdo_cs.transform(geometry, 27700) geom_bng,
sdo_cs.transform(sdo_cs.transform(geometry, 27700), 3785) geom_bng_3785,
sdo_cs.transform(sdo_cs.transform(sdo_cs.transform(geometry, 27700),4326),3785) geom_bng_4326_3785,
sdo_cs.transform(sdo_cs.transform(geometry, 27700), 3857) geom_bng_3857
from cities where iso_a2='UK' and name='London';

NAME
------------------------------
GEOM_BNG(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)
--------------------------------------------------------------------------------
GEOM_BNG_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
GEOM_BNG_4326_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_O
--------------------------------------------------------------------------------
GEOM_BNG_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
London
SDO_GEOMETRY(3001, 27700, SDO_POINT_TYPE(530678.086, 179789.242, 0), NULL, NULL)
SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6677081.27, 0), NULL, NULL)
SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6710566.11, 0), NULL, NULL)
SDO_GEOMETRY(3001, 3857, SDO_POINT_TYPE(-13210.033, 6710566.11, 0), NULL, NULL)

This time they do. 

Monday Jul 22, 2013

Limitations in client side styles (for Vector Layers/FOI) in the V2 API

The V2 API (in MapViewer versions 11.1.1.7.0 and 11.1.1.7.1) currently has some limitations in styles that can be used for vector layers (aka FOI). That is, some styles which can be defined in MapBuilder and used for FOI with the V1 API cannot be used for vector layers in V2.

The current limitations are:

LINE styles in v2 have these limitations:
   1. no dash support (on any part of the line style)
   2. no marker-pattern or built-in arrow head on LINE style

AREA styles that use image as fill pattern: not supported 

TEXT styles:  some labeling hints are not supported, such as sticky, multi-line auto-wrap

DOT density style: not supported in v2



Connecting to a 12c database instance with MapViewer 11.1.1.7.x

The the jdbc connection string (or jdbc url) for a 12c database now requires a service name instead of a SID.

In MapViewer 11.1.1.7.1 the jdbc info in the map_data_source element in the mapviewer configuration file accepts a service name but requires a different syntax. The relevant details (from the README) are

MapViewer native (non-container) data sources can now use database service name in place of SID. 
To supply a db service name, you will use the same jdbc_sid attribute, but specify the service name 
with double slashes in front, e.g.:

  <map_data_source name="myds"
    jdbc_host="foo.com" 
    jdbc_sid="//mypdb1.foo.com" 
    jdbc_port="1522" 
    ... ...
  />

If you're using 11.1.1.7.0 then you need to use a container data source to connect to a 12c instance.

i.e. instead of using

<map_data_source name="my_12c_test"

                   jdbc_host="mydbinstance"
                   jdbc_sid="//pdborcl12c.foo.com"
                   jdbc_port="1522"
                   jdbc_user="mytestuser"
                   jdbc_password="m2E7T48U3LfRjKwR0YFETQcjNb4gCMLG8/X0KWjO00Q="
                   jdbc_mode="thin"
                   number_of_mappers="6"
                   allow_jdbc_theme_based_foi="false"
                   editable="false"
   />
use
  <map_data_source name="my_12c_test"
                   container_ds="jdbc/db12c"
                   number_of_mappers="6"
                   allow_jdbc_theme_based_foi="false"
                   editable="false"
   />

In my case the Glassfish 3.1.2.2 JDBC connection pool definition was:
Property
url  jdbc:oracle:thin:@mydbinstance:1522/pdborcl12c.rest_of.service.name

Uncheck the Wrap JDBC Objects option in Advanced panel, i.e. the Edit JDBC Connection Pool Advanced properties page.
Add a JDBC resource for that newly created pool and use that in mapviewerconfig.xml as above

About

Official blog for Oracle Maps and related products.

Search

Categories
Archives
« July 2016
SunMonTueWedThuFriSat
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
19
20
22
23
24
25
26
27
28
29
30
31
      
Today