Build simple pc app

This commit is contained in:
Victor Shcherb 2012-05-01 01:43:09 +02:00
parent 76643bfc26
commit 535c517d56
16 changed files with 747 additions and 651 deletions

1
Osmand-kernel/freetype/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
build/

View file

@ -1,18 +1,12 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/Common.mk
# compile in ARM mode, since the glyph loader/renderer is a hotspot
# when loading complex pages in the browser
#
LOCAL_ARM_MODE := arm
ifeq ($(OSMAND_FREETYPE_LOC),)
OSMAND_FREETYPE_LOC := ./freetype_library
endif
ifeq ($(OSMAND_FREETYPE_ABS),)
OSMAND_FREETYPE_ABS := $(LOCAL_PATH)/freetype_library
endif
ifneq ($(OSMAND_BUILDING_NEON_LIBRARY),true)
LOCAL_MODULE := ft2_static
else
@ -22,43 +16,6 @@ endif
ifneq ($(OSMAND_USE_PREBUILT),true)
LOCAL_SRC_FILES:= \
$(OSMAND_FREETYPE_LOC)/src/base/ftbbox.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftbitmap.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftfstype.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftglyph.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftlcdfil.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftstroke.c \
$(OSMAND_FREETYPE_LOC)/src/base/fttype1.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftxf86.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftbase.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftsystem.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftinit.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftgasp.c \
$(OSMAND_FREETYPE_LOC)/src/raster/raster.c \
$(OSMAND_FREETYPE_LOC)/src/sfnt/sfnt.c \
$(OSMAND_FREETYPE_LOC)/src/smooth/smooth.c \
$(OSMAND_FREETYPE_LOC)/src/autofit/autofit.c \
$(OSMAND_FREETYPE_LOC)/src/truetype/truetype.c \
$(OSMAND_FREETYPE_LOC)/src/cff/cff.c \
$(OSMAND_FREETYPE_LOC)/src/psnames/psnames.c \
$(OSMAND_FREETYPE_LOC)/src/pshinter/pshinter.c
LOCAL_C_INCLUDES += \
$(OSMAND_FREETYPE_ABS)/builds \
$(OSMAND_FREETYPE_ABS)/include
LOCAL_CFLAGS += -W -Wall
LOCAL_CFLAGS += -fPIC -DPIC
LOCAL_CFLAGS += "-DDARWIN_NO_CARBON"
LOCAL_CFLAGS += "-DFT2_BUILD_LIBRARY"
# the following is for testing only, and should not be used in final builds
# of the product
#LOCAL_CFLAGS += "-DTT_CONFIG_OPTION_BYTECODE_INTERPRETER"
LOCAL_CFLAGS += -O2
include $(BUILD_STATIC_LIBRARY)
else

View file

@ -0,0 +1,41 @@
OSMAND_FREETYPE_LOC := ./freetype_library
OSMAND_FREETYPE_ABS := $(LOCAL_PATH)/freetype_library
LOCAL_SRC_FILES:= \
$(OSMAND_FREETYPE_LOC)/src/base/ftbbox.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftbitmap.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftfstype.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftglyph.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftlcdfil.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftstroke.c \
$(OSMAND_FREETYPE_LOC)/src/base/fttype1.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftxf86.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftbase.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftsystem.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftinit.c \
$(OSMAND_FREETYPE_LOC)/src/base/ftgasp.c \
$(OSMAND_FREETYPE_LOC)/src/raster/raster.c \
$(OSMAND_FREETYPE_LOC)/src/sfnt/sfnt.c \
$(OSMAND_FREETYPE_LOC)/src/smooth/smooth.c \
$(OSMAND_FREETYPE_LOC)/src/autofit/autofit.c \
$(OSMAND_FREETYPE_LOC)/src/truetype/truetype.c \
$(OSMAND_FREETYPE_LOC)/src/cff/cff.c \
$(OSMAND_FREETYPE_LOC)/src/psnames/psnames.c \
$(OSMAND_FREETYPE_LOC)/src/pshinter/pshinter.c
LOCAL_C_INCLUDES += \
$(OSMAND_FREETYPE_ABS)/builds \
$(OSMAND_FREETYPE_ABS)/include
LOCAL_CFLAGS += -W -Wall
LOCAL_CFLAGS += -fPIC -DPIC
LOCAL_CFLAGS += "-DDARWIN_NO_CARBON"
LOCAL_CFLAGS += "-DFT2_BUILD_LIBRARY"
# the following is for testing only, and should not be used in final builds
# of the product
#LOCAL_CFLAGS += "-DTT_CONFIG_OPTION_BYTECODE_INTERPRETER"
LOCAL_CFLAGS += -O2

View file

@ -0,0 +1,24 @@
LOCAL_PATH = .
include Common.mk
CPP_FILE_EXTENSION = c
LIBNAME := libft2.a
PREBUILT_DIR = ../jni-prebuilt/linux-x86/
OBJECTS = $(LOCAL_SRC_FILES:%.$(CPP_FILE_EXTENSION)=build/obj/%.o)
C_INCLUDES := $(addprefix -I, $(LOCAL_C_INCLUDES))
CPPFLAGS = $(LOCAL_CFLAGS) $(C_INCLUDES)
target : $(PREBUILT_DIR)/$(LIBNAME)
$(PREBUILT_DIR)/$(LIBNAME) : build/$(LIBNAME)
cp build/$(LIBNAME) $(PREBUILT_DIR)/$(LIBNAME)
build/$(LIBNAME): $(OBJECTS)
ar -rf build/$(LIBNAME) $(OBJECTS)
build/obj/%.o : %.$(CPP_FILE_EXTENSION) $(LOCAL_C_INCLUDES)
@mkdir -p `dirname $@`
$(CXX) -o $@ -c $*.$(CPP_FILE_EXTENSION) $(CPPFLAGS)
clean:
$(RM) $(OBJECTS) build/$(LIBNAME)

View file

@ -17,6 +17,7 @@ LOCAL_SRC_FILES := \
src/osmand_log.cpp \
src/common.cpp \
src/mapObjects.cpp \
src/multipolygons.cpp \
src/renderRules.cpp \
src/rendering.cpp \
src/binaryRead.cpp

View file

@ -1,10 +1,15 @@
LOCAL_PATH := .
PREBUILT_DIR = ../jni-prebuilt/linux-x86/
LIBNAME := osmand.lib
include Common.mk
RUNFILE := osmand_main
include ./Common.mk
LOCAL_SRC_FILES += src/osmand_main.cpp
LDFLAGS = -Wl,--hash-style=both -shared
LDLIBS = -L$(PREBUILT_DIR) -lskia -lproto
LDRUNFLAGS = -Wl,--hash-style=both
LDLIBS = -L$(PREBUILT_DIR) -lskia -lproto -lpthread -lrt -lft2
CPP_FILE_EXTENSION = cpp
OBJECTS = $(LOCAL_SRC_FILES:src/%.$(CPP_FILE_EXTENSION)=build/obj/%.o)
@ -18,8 +23,16 @@ CPPFLAGS := \
-c -fpic -I$(JAVA_HOME)/include \
-DHAVING_HASH \
$(C_INCLUDES)
target : ../$(RUNFILE)
#target : $(PREBUILT_DIR)/$(LIBNAME) ../$(RUNFILE)
$(PREBUILT_DIR)/$(LIBNAME) : build/$(LIBNAME)
../$(RUNFILE) : $(OBJECTS) $(PREBUILT_DIR)/libskia.a $(PREBUILT_DIR)/libproto.a
$(CXX) $(LDRUNFLAGS) -o ../$(RUNFILE) $(OBJECTS) $(LDLIBS)
@chmod +x ../$(RUNFILE)
$(PREBUILT_DIR)/$(LIBNAME) : build/$(LIBNAME)
cp build/$(LIBNAME) $(PREBUILT_DIR)/$(LIBNAME)

View file

@ -1,15 +1,8 @@
#ifndef _OSMAND_BINARY_READ
#define _OSMAND_BINARY_READ
#include <math.h>
#include <osmand_log.h>
#include <stdio.h>
#include <fstream>
#include <algorithm>
#include <map>
#include <string>
#include "binaryRead.h"
#include "osmand_log.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/wire_format_lite.h"
#include "google/protobuf/wire_format_lite.cc"
@ -18,7 +11,6 @@
#include "common.h"
#include "mapObjects.h"
#include "multipolygons.h"
//#include "multipolygons.h"
#include "proto/osmand_odb.pb.h"
using namespace std;
@ -29,8 +21,6 @@ using namespace google::protobuf::internal;
static const int MAP_VERSION = 2;
static const int BASEMAP_ZOOM = 11;
struct BinaryMapFile;
std::map<std::string, BinaryMapFile*> openFiles;
@ -101,106 +91,6 @@ struct SearchQuery {
}
};
struct MapTreeBounds {
uint32 length;
uint32 filePointer;
uint32 mapDataBlock;
uint32 left ;
uint32 right ;
uint32 top ;
uint32 bottom;
bool ocean;
MapTreeBounds() {
ocean = -1;
}
};
struct MapRoot: MapTreeBounds {
int minZoom ;
int maxZoom ;
std::vector<MapTreeBounds> bounds;
};
struct MapIndex {
uint32 length;
int filePointer;
std::string name;
std::vector<MapRoot> levels;
HMAP::hash_map<int, tag_value > decodingRules;
// DEFINE hash
//HMAP::hash_map<tag_value, int> encodingRules;
int nameEncodingType;
int refEncodingType;
int coastlineEncodingType;
int coastlineBrokenEncodingType;
int landEncodingType;
int onewayAttribute ;
int onewayReverseAttribute ;
HMAP::hash_set< int > positiveLayers;
HMAP::hash_set< int > negativeLayers;
MapIndex(){
nameEncodingType = refEncodingType = coastlineBrokenEncodingType = coastlineEncodingType = -1;
landEncodingType = onewayAttribute = onewayReverseAttribute = -1;
}
void finishInitializingTags() {
int free = decodingRules.size() * 2 + 1;
coastlineBrokenEncodingType = free++;
initMapEncodingRule(0, coastlineBrokenEncodingType, "natural", "coastline_broken");
if (landEncodingType == -1) {
landEncodingType = free++;
initMapEncodingRule(0, landEncodingType, "natural", "land");
}
}
void initMapEncodingRule(uint32 type, uint32 id, std::string tag, std::string val) {
tag_value pair = tag_value(tag, val);
// DEFINE hash
//encodingRules[pair] = id;
decodingRules[id] = pair;
if ("name" == tag) {
nameEncodingType = id;
} else if ("natural" == tag && "coastline" == val) {
coastlineEncodingType = id;
} else if ("natural" == tag && "land" == val) {
landEncodingType = id;
} else if ("oneway" == tag && "yes" == val) {
onewayAttribute = id;
} else if ("oneway" == tag && "-1" == val) {
onewayReverseAttribute = id;
} else if ("ref" == tag) {
refEncodingType = id;
} else if ("layer" == tag) {
if (val != "" && val != "0") {
if (val[0] == '-') {
negativeLayers.insert(id);
} else {
positiveLayers.insert(id);
}
}
}
}
};
struct BinaryMapFile {
std::string inputName;
std::vector<MapIndex> mapIndexes;
FILE* f;
bool basemap;
bool isBasemap(){
return basemap;
}
~BinaryMapFile() {
fclose(f);
}
};
bool readMapTreeBounds(io::CodedInputStream* input, MapTreeBounds* tree, MapRoot* root) {
int init = 0;

View file

@ -0,0 +1,123 @@
#ifndef _OSMAND_BINARY_READ_H
#define _OSMAND_BINARY_READ_H
#include <stdio.h>
#include <fstream>
#include <algorithm>
#include <map>
#include <string>
#include <stdint.h>
#include "google/protobuf/wire_format_lite.h"
#include "common.h"
#include "mapObjects.h"
struct MapTreeBounds {
uint32 length;
uint32 filePointer;
uint32 mapDataBlock;
uint32 left ;
uint32 right ;
uint32 top ;
uint32 bottom;
bool ocean;
MapTreeBounds() {
ocean = -1;
}
};
struct MapRoot: MapTreeBounds {
int minZoom ;
int maxZoom ;
std::vector<MapTreeBounds> bounds;
};
struct MapIndex {
uint32 length;
int filePointer;
std::string name;
std::vector<MapRoot> levels;
HMAP::hash_map<int, tag_value > decodingRules;
// DEFINE hash
//HMAP::hash_map<tag_value, int> encodingRules;
int nameEncodingType;
int refEncodingType;
int coastlineEncodingType;
int coastlineBrokenEncodingType;
int landEncodingType;
int onewayAttribute ;
int onewayReverseAttribute ;
HMAP::hash_set< int > positiveLayers;
HMAP::hash_set< int > negativeLayers;
MapIndex(){
nameEncodingType = refEncodingType = coastlineBrokenEncodingType = coastlineEncodingType = -1;
landEncodingType = onewayAttribute = onewayReverseAttribute = -1;
}
void finishInitializingTags() {
int free = decodingRules.size() * 2 + 1;
coastlineBrokenEncodingType = free++;
initMapEncodingRule(0, coastlineBrokenEncodingType, "natural", "coastline_broken");
if (landEncodingType == -1) {
landEncodingType = free++;
initMapEncodingRule(0, landEncodingType, "natural", "land");
}
}
void initMapEncodingRule(uint32 type, uint32 id, std::string tag, std::string val) {
tag_value pair = tag_value(tag, val);
// DEFINE hash
//encodingRules[pair] = id;
decodingRules[id] = pair;
if ("name" == tag) {
nameEncodingType = id;
} else if ("natural" == tag && "coastline" == val) {
coastlineEncodingType = id;
} else if ("natural" == tag && "land" == val) {
landEncodingType = id;
} else if ("oneway" == tag && "yes" == val) {
onewayAttribute = id;
} else if ("oneway" == tag && "-1" == val) {
onewayReverseAttribute = id;
} else if ("ref" == tag) {
refEncodingType = id;
} else if ("layer" == tag) {
if (val != "" && val != "0") {
if (val[0] == '-') {
negativeLayers.insert(id);
} else {
positiveLayers.insert(id);
}
}
}
}
};
struct BinaryMapFile {
std::string inputName;
std::vector<MapIndex> mapIndexes;
FILE* f;
bool basemap;
bool isBasemap(){
return basemap;
}
~BinaryMapFile() {
fclose(f);
}
};
extern "C" JNIEXPORT jboolean JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_initBinaryMapFile(JNIEnv* ienv,
jobject obj, jobject path);
#endif

View file

@ -8,6 +8,28 @@
#include <hash_map>
#include <hash_set>
#ifdef _MSC_VER
typedef __int8 int8;
typedef __int16 int16;
typedef __int32 int32;
typedef __int64 int64;
typedef unsigned __int8 uint8;
typedef unsigned __int16 uint16;
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;
#else
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
#endif
#ifdef HAVING_HASH
#define HMAP __gnu_cxx

View file

@ -0,0 +1,497 @@
#ifndef _MULTIPOLYGONS_CPP
#define _MULTIPOLYGONS_CPP
#include "multipolygons.h"
#include "osmand_log.h"
void processCoastlines(std::vector<MapDataObject*>& coastLines, int leftX, int rightX, int bottomY, int topY, int zoom,
bool showIncompleted, std::vector<MapDataObject*>& res) {
std::vector<coordinates> completedRings;
std::vector<coordinates > uncompletedRings;
std::vector<MapDataObject*>::iterator val = coastLines.begin();
res.reserve(coastLines.size());
long long dbId = 0;
for (; val != coastLines.end(); val++) {
MapDataObject* o = *val;
int len = o->points.size();
if (len < 2) {
continue;
}
dbId = o->id >> 1;
coordinates* cs = new coordinates();
int px = o->points.at(0).first;
int py = o->points.at(0).second;
int x = px;
int y = py;
bool pinside = leftX <= x && x <= rightX && y >= topY && y <= bottomY;
if (pinside) {
cs->push_back(int_pair(x, y));
}
for (int i = 1; i < len; i++) {
x = o->points.at(i).first;
y = o->points.at(i).second;
bool inside = leftX <= x && x <= rightX && y >= topY && y <= bottomY;
bool lineEnded = calculateLineCoordinates(inside, x, y, pinside, px, py, leftX, rightX, bottomY, topY, *cs);
if (lineEnded) {
combineMultipolygonLine(completedRings, uncompletedRings, *cs);
// create new line if it goes outside
cs = new coordinates();
}
px = x;
py = y;
pinside = inside;
}
combineMultipolygonLine(completedRings, uncompletedRings, *cs);
}
if (completedRings.size() == 0 && uncompletedRings.size() == 0) {
return;
}
if (uncompletedRings.size() > 0) {
unifyIncompletedRings(uncompletedRings, completedRings, leftX, rightX, bottomY, topY, dbId, zoom);
}
if (!showIncompleted && uncompletedRings.size() > 0) {
res.clear();
return;
}
bool clockwiseFound = false;
for (int i = 0; i < completedRings.size(); i++) {
bool clockwise = isClockwiseWay(completedRings[i]);
clockwiseFound = clockwiseFound || clockwise;
MapDataObject* o = new MapDataObject();
o->points = completedRings[i];
if (clockwise) {
o->types.push_back(tag_value("natural", "coastline"));
} else {
o->types.push_back(tag_value("natural", "land"));
}
o->id = dbId;
o->area = true;
res.push_back(o);
}
// draw uncompleted for debug purpose
for (int i = 0; i < uncompletedRings.size(); i++) {
MapDataObject* o = new MapDataObject();
o->points = uncompletedRings[i];
o->types.push_back(tag_value("natural", "coastline_broken"));
//res.push_back(o);
}
if (!clockwiseFound && uncompletedRings.size() == 0) {
// add complete water tile
MapDataObject* o = new MapDataObject();
o->points.push_back(int_pair(leftX, topY));
o->points.push_back(int_pair(rightX, topY));
o->points.push_back(int_pair(rightX, bottomY));
o->points.push_back(int_pair(leftX, bottomY));
o->points.push_back(int_pair(leftX, topY));
o->id = dbId;
o->types.push_back(tag_value("natural", "coastline"));
osmand_log_print(LOG_ERROR, "!!! Isolated islands !!!");
res.push_back(o);
}
}
// Copied from MapAlgorithms
int ray_intersect_x(int prevX, int prevY, int x, int y, int middleY) {
// prev node above line
// x,y node below line
if (prevY > y) {
int tx = x;
int ty = y;
x = prevX;
y = prevY;
prevX = tx;
prevY = ty;
}
if (y == middleY || prevY == middleY) {
middleY -= 1;
}
if (prevY > middleY || y < middleY) {
return INT_MIN;
} else {
if (y == prevY) {
// the node on the boundary !!!
return x;
}
// that tested on all cases (left/right)
double rx = x + ((double) middleY - y) * ((double) x - prevX) / (((double) y - prevY));
return (int) rx;
}
}
// Copied from MapAlgorithms
bool isClockwiseWay(std::vector<int_pair>& c) {
if (c.size() == 0) {
return true;
}
// calculate middle Y
long long middleY = 0;
for (size_t i = 0; i < c.size(); i++) {
middleY += c.at(i).second;
}
middleY /= (long long) c.size();
double clockwiseSum = 0;
bool firstDirectionUp = false;
int previousX = INT_MIN;
int firstX = INT_MIN;
int prevX = c.at(0).first;
int prevY = c.at(0).second;
for (size_t i = 1; i < c.size(); i++) {
int x = c.at(i).first;
int y = c.at(i).second;
int rX = ray_intersect_x(prevX, prevY, x, y, (int) middleY);
if (rX != INT_MIN) {
bool skipSameSide = (y <= middleY) == (prevY <= middleY);
if (skipSameSide) {
continue;
}
bool directionUp = prevY >= middleY;
if (firstX == INT_MIN) {
firstDirectionUp = directionUp;
firstX = rX;
} else {
bool clockwise = (!directionUp) == (previousX < rX);
if (clockwise) {
clockwiseSum += abs(previousX - rX);
} else {
clockwiseSum -= abs(previousX - rX);
}
}
previousX = rX;
}
prevX = x;
prevY = y;
}
if (firstX != INT_MIN) {
bool clockwise = (!firstDirectionUp) == (previousX < firstX);
if (clockwise) {
clockwiseSum += abs(previousX - firstX);
} else {
clockwiseSum -= abs(previousX - firstX);
}
}
return clockwiseSum >= 0;
}
void combineMultipolygonLine(std::vector<coordinates>& completedRings, std::vector<coordinates>& incompletedRings,
coordinates& coordinates) {
if (coordinates.size() > 0) {
if (coordinates.at(0) == coordinates.at(coordinates.size() - 1)) {
completedRings.push_back(coordinates);
} else {
bool add = true;
for (size_t k = 0; k < incompletedRings.size();) {
bool remove = false;
std::vector<int_pair> i = incompletedRings.at(k);
if (coordinates.at(0) == i.at(i.size() - 1)) {
std::vector<int_pair>::iterator tit = coordinates.begin();
i.insert(i.end(), ++tit, coordinates.end());
remove = true;
coordinates = i;
} else if (coordinates.at(coordinates.size() - 1) == i.at(0)) {
std::vector<int_pair>::iterator tit = i.begin();
coordinates.insert(coordinates.end(), ++tit, i.end());
remove = true;
}
if (remove) {
std::vector<std::vector<int_pair> >::iterator ti = incompletedRings.begin();
ti += k;
incompletedRings.erase(ti);
} else {
k++;
}
if (coordinates.at(0) == coordinates.at(coordinates.size() - 1)) {
completedRings.push_back(coordinates);
add = false;
break;
}
}
if (add) {
incompletedRings.push_back(coordinates);
}
}
}
}
int safelyAddDelta(int number, int delta) {
int res = number + delta;
if (delta > 0 && res < number) {
return INT_MAX;
} else if (delta < 0 && res > number) {
return INT_MIN;
}
return res;
}
void unifyIncompletedRings(std::vector<std::vector<int_pair> >& toProccess, std::vector<std::vector<int_pair> >& completedRings,
int leftX, int rightX, int bottomY, int topY, long dbId, int zoom) {
std::set<int> nonvisitedRings;
std::vector<coordinates > incompletedRings(toProccess);
toProccess.clear();
std::vector<coordinates >::iterator ir = incompletedRings.begin();
int j = 0;
for (j = 0; ir != incompletedRings.end(); ir++,j++) {
int x = ir->at(0).first;
int y = ir->at(0).second;
int sx = ir->at(ir->size() - 1).first;
int sy = ir->at(ir->size() - 1).second;
bool st = y == topY || x == rightX || y == bottomY || x == leftX;
bool end = sy == topY || sx == rightX || sy == bottomY || sx == leftX;
// something goes wrong
// These exceptions are used to check logic about processing multipolygons
// However this situation could happen because of broken multipolygons (so it should data causes app error)
// that's why these exceptions could be replaced with return; statement.
if (!end || !st) {
osmand_log_print(LOG_ERROR, "Error processing multipolygon");
toProccess.push_back(*ir);
} else {
nonvisitedRings.insert(j);
}
}
ir = incompletedRings.begin();
for (j = 0; ir != incompletedRings.end(); ir++, j++) {
if (nonvisitedRings.find(j) == nonvisitedRings.end()) {
continue;
}
int x = ir->at(ir->size() - 1).first;
int y = ir->at(ir->size() - 1).second;
// 31 - (zoom + 8)
const int EVAL_DELTA = 6 << (23 - zoom);
const int UNDEFINED_MIN_DIFF = -1 - EVAL_DELTA;
while (true) {
int st = 0; // st already checked to be one of the four
if (y == topY) {
st = 0;
} else if (x == rightX) {
st = 1;
} else if (y == bottomY) {
st = 2;
} else if (x == leftX) {
st = 3;
}
int nextRingIndex = -1;
// BEGIN go clockwise around rectangle
for (int h = st; h < st + 4; h++) {
// BEGIN find closest nonvisited start (including current)
int mindiff = UNDEFINED_MIN_DIFF;
std::vector<std::vector<int_pair> >::iterator cni = incompletedRings.begin();
int cnik = 0;
for (;cni != incompletedRings.end(); cni++, cnik ++) {
if (nonvisitedRings.find(cnik) == nonvisitedRings.end()) {
continue;
}
int csx = cni->at(0).first;
int csy = cni->at(0).second;
if (h % 4 == 0) {
// top
if (csy == topY && csx >= safelyAddDelta(x, -EVAL_DELTA)) {
if (mindiff == UNDEFINED_MIN_DIFF || (csx - x) <= mindiff) {
mindiff = (csx - x);
nextRingIndex = cnik;
}
}
} else if (h % 4 == 1) {
// right
if (csx == rightX && csy >= safelyAddDelta(y, -EVAL_DELTA)) {
if (mindiff == UNDEFINED_MIN_DIFF || (csy - y) <= mindiff) {
mindiff = (csy - y);
nextRingIndex = cnik;
}
}
} else if (h % 4 == 2) {
// bottom
if (csy == bottomY && csx <= safelyAddDelta(x, EVAL_DELTA)) {
if (mindiff == UNDEFINED_MIN_DIFF || (x - csx) <= mindiff) {
mindiff = (x - csx);
nextRingIndex = cnik;
}
}
} else if (h % 4 == 3) {
// left
if (csx == leftX && csy <= safelyAddDelta(y, EVAL_DELTA)) {
if (mindiff == UNDEFINED_MIN_DIFF || (y - csy) <= mindiff) {
mindiff = (y - csy);
nextRingIndex = cnik;
}
}
}
} // END find closest start (including current)
// we found start point
if (mindiff != UNDEFINED_MIN_DIFF) {
break;
} else {
if (h % 4 == 0) {
// top
y = topY;
x = rightX;
} else if (h % 4 == 1) {
// right
y = bottomY;
x = rightX;
} else if (h % 4 == 2) {
// bottom
y = bottomY;
x = leftX;
} else if (h % 4 == 3) {
y = topY;
x = leftX;
}
ir->push_back(int_pair(x, y));
}
} // END go clockwise around rectangle
if (nextRingIndex == -1) {
// it is impossible (current start should always be found)
} else if (nextRingIndex == j) {
ir->push_back(ir->at(0));
nonvisitedRings.erase(j);
break;
} else {
std::vector<int_pair> p = incompletedRings.at(nextRingIndex);
ir->insert(ir->end(), p.begin(), p.end());
nonvisitedRings.erase(nextRingIndex);
// get last point and start again going clockwise
x = ir->at(ir->size() - 1).first;
y = ir->at(ir->size() - 1).second;
}
}
completedRings.push_back(*ir);
}
}
/**
* @return -1 if there is no instersection or x<<32 | y
*/
bool calculateIntersection(int x, int y, int px, int py, int leftX, int rightX, int bottomY, int topY, int_pair& b) {
// firstly try to search if the line goes in
if (py < topY && y >= topY) {
int tx = (int) (px + ((double) (x - px) * (topY - py)) / (y - py));
if (leftX <= tx && tx <= rightX) {
b.first = tx;
b.second = topY;
return true;
}
}
if (py > bottomY && y <= bottomY) {
int tx = (int) (px + ((double) (x - px) * (py - bottomY)) / (py - y));
if (leftX <= tx && tx <= rightX) {
b.first = tx;
b.second = bottomY;
return true;
}
}
if (px < leftX && x >= leftX) {
int ty = (int) (py + ((double) (y - py) * (leftX - px)) / (x - px));
if (ty >= topY && ty <= bottomY) {
b.first = leftX;
b.second = ty;
return true;
}
}
if (px > rightX && x <= rightX) {
int ty = (int) (py + ((double) (y - py) * (px - rightX)) / (px - x));
if (ty >= topY && ty <= bottomY) {
b.first = rightX;
b.second = ty;
return true;
}
}
// try to search if point goes out
if (py > topY && y <= topY) {
int tx = (int) (px + ((double) (x - px) * (topY - py)) / (y - py));
if (leftX <= tx && tx <= rightX) {
b.first = tx;
b.second = topY;
return true;
}
}
if (py < bottomY && y >= bottomY) {
int tx = (int) (px + ((double) (x - px) * (py - bottomY)) / (py - y));
if (leftX <= tx && tx <= rightX) {
b.first = tx;
b.second = bottomY;
return true;
}
}
if (px > leftX && x <= leftX) {
int ty = (int) (py + ((double) (y - py) * (leftX - px)) / (x - px));
if (ty >= topY && ty <= bottomY) {
b.first = leftX;
b.second = ty;
return true;
}
}
if (px < rightX && x >= rightX) {
int ty = (int) (py + ((double) (y - py) * (px - rightX)) / (px - x));
if (ty >= topY && ty <= bottomY) {
b.first = rightX;
b.second = ty;
return true;
}
}
if (px == rightX || px == leftX || py == topY || py == bottomY) {
b.first = px;
b.second = py;
// return true;
// Is it right? to not return anything?
}
return false;
}
bool calculateLineCoordinates(bool inside, int x, int y, bool pinside, int px, int py, int leftX, int rightX,
int bottomY, int topY, std::vector<int_pair>& coordinates) {
bool lineEnded = false;
int_pair b(x, y);
if (pinside) {
if (!inside) {
bool is = calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY, b);
if (!is) {
b.first = px;
b.second = py;
}
coordinates.push_back(b);
lineEnded = true;
} else {
coordinates.push_back(b);
}
} else {
bool is = calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY, b);
if (inside) {
// assert is != -1;
coordinates.push_back(b);
int_pair n(x, y);
coordinates.push_back(n);
} else if (is) {
coordinates.push_back(b);
calculateIntersection(x, y, b.first, b.second, leftX, rightX, bottomY, topY, b);
coordinates.push_back(b);
lineEnded = true;
}
}
return lineEnded;
}
#endif

View file

@ -1,3 +1,5 @@
#ifndef _MULTIPOLYGONS_H
#define _MULTIPOLYGONS_H
#include <stdio.h>
#include <map>
@ -9,6 +11,7 @@
/// !!! Fuly copied from MapRenderRepositories.java, should be carefully synchroinized
bool isClockwiseWay(std::vector<int_pair>& c) ;
bool calculateLineCoordinates(bool inside, int x, int y, bool pinside, int px, int py, int leftX, int rightX,
int bottomY, int topY, std::vector<int_pair>& coordinates);
@ -20,491 +23,6 @@ void unifyIncompletedRings(std::vector<std::vector<int_pair> >& incompletedRings
void processCoastlines(std::vector<MapDataObject*>& coastLines, int leftX, int rightX, int bottomY, int topY, int zoom,
bool showIncompleted, std::vector<MapDataObject*>& res) {
std::vector<coordinates> completedRings;
std::vector<coordinates > uncompletedRings;
std::vector<MapDataObject*>::iterator val = coastLines.begin();
res.reserve(coastLines.size());
long long dbId = 0;
for (; val != coastLines.end(); val++) {
MapDataObject* o = *val;
int len = o->points.size();
if (len < 2) {
continue;
}
dbId = o->id >> 1;
coordinates* cs = new coordinates();
int px = o->points.at(0).first;
int py = o->points.at(0).second;
int x = px;
int y = py;
bool pinside = leftX <= x && x <= rightX && y >= topY && y <= bottomY;
if (pinside) {
cs->push_back(int_pair(x, y));
}
for (int i = 1; i < len; i++) {
x = o->points.at(i).first;
y = o->points.at(i).second;
bool inside = leftX <= x && x <= rightX && y >= topY && y <= bottomY;
bool lineEnded = calculateLineCoordinates(inside, x, y, pinside, px, py, leftX, rightX, bottomY, topY, *cs);
if (lineEnded) {
combineMultipolygonLine(completedRings, uncompletedRings, *cs);
// create new line if it goes outside
cs = new coordinates();
}
px = x;
py = y;
pinside = inside;
}
combineMultipolygonLine(completedRings, uncompletedRings, *cs);
}
if (completedRings.size() == 0 && uncompletedRings.size() == 0) {
return;
}
if (uncompletedRings.size() > 0) {
unifyIncompletedRings(uncompletedRings, completedRings, leftX, rightX, bottomY, topY, dbId, zoom);
}
if (!showIncompleted && uncompletedRings.size() > 0) {
res.clear();
return;
}
bool clockwiseFound = false;
for (int i = 0; i < completedRings.size(); i++) {
bool clockwise = isClockwiseWay(completedRings[i]);
clockwiseFound = clockwiseFound || clockwise;
MapDataObject* o = new MapDataObject();
o->points = completedRings[i];
if (clockwise) {
o->types.push_back(tag_value("natural", "coastline"));
} else {
o->types.push_back(tag_value("natural", "land"));
}
o->id = dbId;
o->area = true;
res.push_back(o);
}
bool showIncompleted, std::vector<MapDataObject*>& res);
// draw uncompleted for debug purpose
for (int i = 0; i < uncompletedRings.size(); i++) {
MapDataObject* o = new MapDataObject();
o->points = uncompletedRings[i];
o->types.push_back(tag_value("natural", "coastline_broken"));
//res.push_back(o);
}
if (!clockwiseFound && uncompletedRings.size() == 0) {
// add complete water tile
MapDataObject* o = new MapDataObject();
o->points.push_back(int_pair(leftX, topY));
o->points.push_back(int_pair(rightX, topY));
o->points.push_back(int_pair(rightX, bottomY));
o->points.push_back(int_pair(leftX, bottomY));
o->points.push_back(int_pair(leftX, topY));
o->id = dbId;
o->types.push_back(tag_value("natural", "coastline"));
osmand_log_print(LOG_ERROR, "!!! Isolated islands !!!");
res.push_back(o);
}
}
// Copied from MapAlgorithms
int ray_intersect_x(int prevX, int prevY, int x, int y, int middleY) {
// prev node above line
// x,y node below line
if (prevY > y) {
int tx = x;
int ty = y;
x = prevX;
y = prevY;
prevX = tx;
prevY = ty;
}
if (y == middleY || prevY == middleY) {
middleY -= 1;
}
if (prevY > middleY || y < middleY) {
return INT_MIN;
} else {
if (y == prevY) {
// the node on the boundary !!!
return x;
}
// that tested on all cases (left/right)
double rx = x + ((double) middleY - y) * ((double) x - prevX) / (((double) y - prevY));
return (int) rx;
}
}
// Copied from MapAlgorithms
bool isClockwiseWay(std::vector<int_pair>& c) {
if (c.size() == 0) {
return true;
}
// calculate middle Y
long long middleY = 0;
for (size_t i = 0; i < c.size(); i++) {
middleY += c.at(i).second;
}
middleY /= (long long) c.size();
double clockwiseSum = 0;
bool firstDirectionUp = false;
int previousX = INT_MIN;
int firstX = INT_MIN;
int prevX = c.at(0).first;
int prevY = c.at(0).second;
for (size_t i = 1; i < c.size(); i++) {
int x = c.at(i).first;
int y = c.at(i).second;
int rX = ray_intersect_x(prevX, prevY, x, y, (int) middleY);
if (rX != INT_MIN) {
bool skipSameSide = (y <= middleY) == (prevY <= middleY);
if (skipSameSide) {
continue;
}
bool directionUp = prevY >= middleY;
if (firstX == INT_MIN) {
firstDirectionUp = directionUp;
firstX = rX;
} else {
bool clockwise = (!directionUp) == (previousX < rX);
if (clockwise) {
clockwiseSum += abs(previousX - rX);
} else {
clockwiseSum -= abs(previousX - rX);
}
}
previousX = rX;
}
prevX = x;
prevY = y;
}
if (firstX != INT_MIN) {
bool clockwise = (!firstDirectionUp) == (previousX < firstX);
if (clockwise) {
clockwiseSum += abs(previousX - firstX);
} else {
clockwiseSum -= abs(previousX - firstX);
}
}
return clockwiseSum >= 0;
}
void combineMultipolygonLine(std::vector<coordinates>& completedRings, std::vector<coordinates>& incompletedRings,
coordinates& coordinates) {
if (coordinates.size() > 0) {
if (coordinates.at(0) == coordinates.at(coordinates.size() - 1)) {
completedRings.push_back(coordinates);
} else {
bool add = true;
for (size_t k = 0; k < incompletedRings.size();) {
bool remove = false;
std::vector<int_pair> i = incompletedRings.at(k);
if (coordinates.at(0) == i.at(i.size() - 1)) {
std::vector<int_pair>::iterator tit = coordinates.begin();
i.insert(i.end(), ++tit, coordinates.end());
remove = true;
coordinates = i;
} else if (coordinates.at(coordinates.size() - 1) == i.at(0)) {
std::vector<int_pair>::iterator tit = i.begin();
coordinates.insert(coordinates.end(), ++tit, i.end());
remove = true;
}
if (remove) {
std::vector<std::vector<int_pair> >::iterator ti = incompletedRings.begin();
ti += k;
incompletedRings.erase(ti);
} else {
k++;
}
if (coordinates.at(0) == coordinates.at(coordinates.size() - 1)) {
completedRings.push_back(coordinates);
add = false;
break;
}
}
if (add) {
incompletedRings.push_back(coordinates);
}
}
}
}
int safelyAddDelta(int number, int delta) {
int res = number + delta;
if (delta > 0 && res < number) {
return INT_MAX;
} else if (delta < 0 && res > number) {
return INT_MIN;
}
return res;
}
void unifyIncompletedRings(std::vector<std::vector<int_pair> >& toProccess, std::vector<std::vector<int_pair> >& completedRings,
int leftX, int rightX, int bottomY, int topY, long dbId, int zoom) {
std::set<int> nonvisitedRings;
std::vector<coordinates > incompletedRings(toProccess);
toProccess.clear();
std::vector<coordinates >::iterator ir = incompletedRings.begin();
int j = 0;
for (j = 0; ir != incompletedRings.end(); ir++,j++) {
int x = ir->at(0).first;
int y = ir->at(0).second;
int sx = ir->at(ir->size() - 1).first;
int sy = ir->at(ir->size() - 1).second;
bool st = y == topY || x == rightX || y == bottomY || x == leftX;
bool end = sy == topY || sx == rightX || sy == bottomY || sx == leftX;
// something goes wrong
// These exceptions are used to check logic about processing multipolygons
// However this situation could happen because of broken multipolygons (so it should data causes app error)
// that's why these exceptions could be replaced with return; statement.
if (!end || !st) {
osmand_log_print(LOG_ERROR, "Error processing multipolygon");
toProccess.push_back(*ir);
} else {
nonvisitedRings.insert(j);
}
}
ir = incompletedRings.begin();
for (j = 0; ir != incompletedRings.end(); ir++, j++) {
if (nonvisitedRings.find(j) == nonvisitedRings.end()) {
continue;
}
int x = ir->at(ir->size() - 1).first;
int y = ir->at(ir->size() - 1).second;
// 31 - (zoom + 8)
const int EVAL_DELTA = 6 << (23 - zoom);
const int UNDEFINED_MIN_DIFF = -1 - EVAL_DELTA;
while (true) {
int st = 0; // st already checked to be one of the four
if (y == topY) {
st = 0;
} else if (x == rightX) {
st = 1;
} else if (y == bottomY) {
st = 2;
} else if (x == leftX) {
st = 3;
}
int nextRingIndex = -1;
// BEGIN go clockwise around rectangle
for (int h = st; h < st + 4; h++) {
// BEGIN find closest nonvisited start (including current)
int mindiff = UNDEFINED_MIN_DIFF;
std::vector<std::vector<int_pair> >::iterator cni = incompletedRings.begin();
int cnik = 0;
for (;cni != incompletedRings.end(); cni++, cnik ++) {
if (nonvisitedRings.find(cnik) == nonvisitedRings.end()) {
continue;
}
int csx = cni->at(0).first;
int csy = cni->at(0).second;
if (h % 4 == 0) {
// top
if (csy == topY && csx >= safelyAddDelta(x, -EVAL_DELTA)) {
if (mindiff == UNDEFINED_MIN_DIFF || (csx - x) <= mindiff) {
mindiff = (csx - x);
nextRingIndex = cnik;
}
}
} else if (h % 4 == 1) {
// right
if (csx == rightX && csy >= safelyAddDelta(y, -EVAL_DELTA)) {
if (mindiff == UNDEFINED_MIN_DIFF || (csy - y) <= mindiff) {
mindiff = (csy - y);
nextRingIndex = cnik;
}
}
} else if (h % 4 == 2) {
// bottom
if (csy == bottomY && csx <= safelyAddDelta(x, EVAL_DELTA)) {
if (mindiff == UNDEFINED_MIN_DIFF || (x - csx) <= mindiff) {
mindiff = (x - csx);
nextRingIndex = cnik;
}
}
} else if (h % 4 == 3) {
// left
if (csx == leftX && csy <= safelyAddDelta(y, EVAL_DELTA)) {
if (mindiff == UNDEFINED_MIN_DIFF || (y - csy) <= mindiff) {
mindiff = (y - csy);
nextRingIndex = cnik;
}
}
}
} // END find closest start (including current)
// we found start point
if (mindiff != UNDEFINED_MIN_DIFF) {
break;
} else {
if (h % 4 == 0) {
// top
y = topY;
x = rightX;
} else if (h % 4 == 1) {
// right
y = bottomY;
x = rightX;
} else if (h % 4 == 2) {
// bottom
y = bottomY;
x = leftX;
} else if (h % 4 == 3) {
y = topY;
x = leftX;
}
ir->push_back(int_pair(x, y));
}
} // END go clockwise around rectangle
if (nextRingIndex == -1) {
// it is impossible (current start should always be found)
} else if (nextRingIndex == j) {
ir->push_back(ir->at(0));
nonvisitedRings.erase(j);
break;
} else {
std::vector<int_pair> p = incompletedRings.at(nextRingIndex);
ir->insert(ir->end(), p.begin(), p.end());
nonvisitedRings.erase(nextRingIndex);
// get last point and start again going clockwise
x = ir->at(ir->size() - 1).first;
y = ir->at(ir->size() - 1).second;
}
}
completedRings.push_back(*ir);
}
}
/**
* @return -1 if there is no instersection or x<<32 | y
*/
bool calculateIntersection(int x, int y, int px, int py, int leftX, int rightX, int bottomY, int topY, int_pair& b) {
// firstly try to search if the line goes in
if (py < topY && y >= topY) {
int tx = (int) (px + ((double) (x - px) * (topY - py)) / (y - py));
if (leftX <= tx && tx <= rightX) {
b.first = tx;
b.second = topY;
return true;
}
}
if (py > bottomY && y <= bottomY) {
int tx = (int) (px + ((double) (x - px) * (py - bottomY)) / (py - y));
if (leftX <= tx && tx <= rightX) {
b.first = tx;
b.second = bottomY;
return true;
}
}
if (px < leftX && x >= leftX) {
int ty = (int) (py + ((double) (y - py) * (leftX - px)) / (x - px));
if (ty >= topY && ty <= bottomY) {
b.first = leftX;
b.second = ty;
return true;
}
}
if (px > rightX && x <= rightX) {
int ty = (int) (py + ((double) (y - py) * (px - rightX)) / (px - x));
if (ty >= topY && ty <= bottomY) {
b.first = rightX;
b.second = ty;
return true;
}
}
// try to search if point goes out
if (py > topY && y <= topY) {
int tx = (int) (px + ((double) (x - px) * (topY - py)) / (y - py));
if (leftX <= tx && tx <= rightX) {
b.first = tx;
b.second = topY;
return true;
}
}
if (py < bottomY && y >= bottomY) {
int tx = (int) (px + ((double) (x - px) * (py - bottomY)) / (py - y));
if (leftX <= tx && tx <= rightX) {
b.first = tx;
b.second = bottomY;
return true;
}
}
if (px > leftX && x <= leftX) {
int ty = (int) (py + ((double) (y - py) * (leftX - px)) / (x - px));
if (ty >= topY && ty <= bottomY) {
b.first = leftX;
b.second = ty;
return true;
}
}
if (px < rightX && x >= rightX) {
int ty = (int) (py + ((double) (y - py) * (px - rightX)) / (px - x));
if (ty >= topY && ty <= bottomY) {
b.first = rightX;
b.second = ty;
return true;
}
}
if (px == rightX || px == leftX || py == topY || py == bottomY) {
b.first = px;
b.second = py;
// return true;
// Is it right? to not return anything?
}
return false;
}
bool calculateLineCoordinates(bool inside, int x, int y, bool pinside, int px, int py, int leftX, int rightX,
int bottomY, int topY, std::vector<int_pair>& coordinates) {
bool lineEnded = false;
int_pair b(x, y);
if (pinside) {
if (!inside) {
bool is = calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY, b);
if (!is) {
b.first = px;
b.second = py;
}
coordinates.push_back(b);
lineEnded = true;
} else {
coordinates.push_back(b);
}
} else {
bool is = calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY, b);
if (inside) {
// assert is != -1;
coordinates.push_back(b);
int_pair n(x, y);
coordinates.push_back(n);
} else if (is) {
coordinates.push_back(b);
calculateIntersection(x, y, b.first, b.second, leftX, rightX, bottomY, topY, b);
coordinates.push_back(b);
lineEnded = true;
}
}
return lineEnded;
}
#endif

View file

@ -25,7 +25,7 @@ void osmand_log_print(int type, const char* msg, ...) {
va_list args;
va_start( args, msg);
// TODO by type
printf(msg, msg, args);
printf(msg, args);
va_end(args);
}

View file

@ -0,0 +1,6 @@
#include "binaryRead.h"
int main() {
printf("Hello world \n");
}

BIN
Osmand-kernel/osmand_main Executable file

Binary file not shown.

View file

@ -1,7 +1,9 @@
include Common.mk
CPP_FILE_EXTENSION = cpp
LIBNAME := libproto.a
PREBUILT_DIR = ../jni-prebuilt/linux-x86/
OBJECTS = $(LOCAL_SRC_FILES:%.cc=build/obj/%.o)
OBJECTS = $(LOCAL_SRC_FILES:%.$(CPP_FILE_EXTENSION)=build/obj/%.o)
CPPFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI -I.
LDLIBS = -lpthread
@ -13,9 +15,9 @@ $(PREBUILT_DIR)/$(LIBNAME) : build/$(LIBNAME)
build/$(LIBNAME): $(OBJECTS)
ar -rf build/$(LIBNAME) $(OBJECTS)
build/obj/%.o :
build/obj/%.o : %.$(CPP_FILE_EXTENSION) $(LOCAL_C_INCLUDES)
@mkdir -p `dirname $@`
$(CXX) -o $@ -c $*.cc $(CPPFLAGS)
$(CXX) -o $@ -c $*.$(CPP_FILE_EXTENSION) $(CPPFLAGS)
clean:
$(RM) $(OBJECTS) build/$(LIBNAME)

View file

@ -12,6 +12,7 @@ LOCAL_SRC_FILES += \
$(OSMAND_SKIA_LOC)/src/ports/SkThread_pthread.cpp \
$(OSMAND_SKIA_LOC)/src/ports/SkDebug_stdio.cpp \
$(OSMAND_SKIA_LOC)/src/ports/SkFontHost_FreeType.cpp \
$(OSMAND_SKIA_LOC)/src/ports/SkFontHost_linux.cpp \
$(OSMAND_SKIA_LOC)/src/ports/SkOSFile_stdio.cpp \
$(OSMAND_SKIA_LOC)/src/ports/SkTime_Unix.cpp \
$(OSMAND_SKIA_LOC)/src/ports/SkMemory_malloc.cpp \
@ -40,7 +41,7 @@ build/$(LIBNAME): $(OBJECTS)
ar -rf build/$(LIBNAME) $(OBJECTS)
cp build/$(LIBNAME) ../jni-prebuilt/linux-x86/$(LIBNAME)
build/obj/%.o :
build/obj/%.o : %.$(CPP_FILE_EXTENSION) $(LOCAL_C_INCLUDES)
@mkdir -p `dirname $@`
$(CXX) -o $@ -c $*.$(CPP_FILE_EXTENSION) $(CPPFLAGS)