467 lines
14 KiB
C++
467 lines
14 KiB
C++
#ifndef ROAD_LINES_DATA_H
|
|
#define ROAD_LINES_DATA_H
|
|
#include <cassert>
|
|
#include <unordered_map>
|
|
#include <core/io/json.h>
|
|
#include <scene/resources/curve.h>
|
|
#include "callable.h"
|
|
class ImmediateGeometry;
|
|
class RoadLinesData {
|
|
int debug_flags;
|
|
String road_lines_path;
|
|
uint32_t road_lines_hash(const Vector3 &v);
|
|
static ImmediateGeometry *debug_im;
|
|
bool initialized;
|
|
|
|
protected:
|
|
RoadLinesData();
|
|
static RoadLinesData *singleton;
|
|
_Signal<void> lines_updated;
|
|
|
|
public:
|
|
struct line_segment {
|
|
Vector3 p1;
|
|
Vector3 p2;
|
|
float length;
|
|
Vector3 dir;
|
|
Vector3 tangent;
|
|
float offset;
|
|
};
|
|
|
|
public:
|
|
struct test_edge;
|
|
struct road_edge;
|
|
struct road_line;
|
|
struct road_edge_side {
|
|
const RoadLinesData::road_edge &edge;
|
|
Vector3 normal;
|
|
Vector3 pmid[2];
|
|
Vector3 pside[2];
|
|
Vector3 test_p[2];
|
|
std::vector<Vector3> lot_points;
|
|
int transit_stop_count;
|
|
String transit_stop_type;
|
|
float transit_stop_offset;
|
|
float transit_stop_dir_offset;
|
|
float transit_stop_y_rotation;
|
|
int sideroad;
|
|
float sideroad_offset;
|
|
float sideroad_dir_offset;
|
|
float sideroad_y_offset;
|
|
float sideroad_y_rotation;
|
|
String sideroad_type;
|
|
int lot;
|
|
float lot_offset;
|
|
float lot_dir_offset;
|
|
float lot_y_offset;
|
|
float lot_y_rotation;
|
|
String lot_type;
|
|
|
|
float lot_depth;
|
|
/* calculated */
|
|
float lot_depth_eff;
|
|
|
|
public:
|
|
struct buildings {
|
|
String id;
|
|
Vector3 offsets;
|
|
float y_rotation;
|
|
String to_string() const
|
|
{
|
|
String ret;
|
|
ret += id + ":";
|
|
ret += String::num(offsets.x) + ", ";
|
|
ret += String::num(offsets.y) + ", ";
|
|
ret += String::num(offsets.z) + ":";
|
|
ret += String::num(y_rotation);
|
|
return ret;
|
|
}
|
|
static void from_string(struct buildings &buildings,
|
|
const String &data)
|
|
{
|
|
Vector<String> parts = data.split(":");
|
|
if (parts.size() < 3)
|
|
return;
|
|
assert(parts.size() == 3);
|
|
Vector<String> vecparts = parts[1].split(",");
|
|
assert(vecparts.size() == 3);
|
|
buildings.id = parts[0];
|
|
buildings.offsets.x =
|
|
vecparts[0].strip_edges().to_float();
|
|
buildings.offsets.y =
|
|
vecparts[1].strip_edges().to_float();
|
|
buildings.offsets.z =
|
|
vecparts[2].strip_edges().to_float();
|
|
buildings.y_rotation =
|
|
parts[2].strip_edges().to_float();
|
|
}
|
|
};
|
|
std::vector<struct buildings> buildings;
|
|
Dictionary to_dict() const
|
|
{
|
|
Dictionary ret;
|
|
ret["transit_stop_count"] = transit_stop_count;
|
|
ret["transit_stop_type"] = transit_stop_type;
|
|
ret["transit_stop_offset"] = transit_stop_offset;
|
|
ret["transit_stop_dir_offset"] =
|
|
transit_stop_dir_offset;
|
|
ret["transit_stop_y_rotation"] =
|
|
transit_stop_y_rotation;
|
|
ret["sideroad"] = sideroad;
|
|
ret["sideroad_offset"] = sideroad_offset;
|
|
ret["sideroad_dir_offset"] = sideroad_dir_offset;
|
|
ret["sideroad_y_offset"] = sideroad_y_offset;
|
|
ret["sideroad_y_rotation"] = sideroad_y_rotation;
|
|
ret["sideroad_type"] = sideroad_type;
|
|
ret["lot"] = lot;
|
|
ret["lot_depth"] = lot_depth;
|
|
ret["lot_offset"] = lot_offset;
|
|
ret["lot_dir_offset"] = lot_dir_offset;
|
|
ret["lot_y_offset"] = lot_y_offset;
|
|
ret["lot_y_rotation"] = lot_y_rotation;
|
|
ret["lot_type"] = lot_type;
|
|
String lot_buildings;
|
|
int i;
|
|
for (i = 0; i < (int)buildings.size(); i++) {
|
|
lot_buildings += buildings[i].to_string();
|
|
if (i < (int)buildings.size() - 1)
|
|
lot_buildings += "!";
|
|
}
|
|
ret["lot_buildings"] = lot_buildings;
|
|
return ret;
|
|
}
|
|
road_edge_side(const RoadLinesData::road_edge &edge)
|
|
: edge(edge)
|
|
, transit_stop_count(0)
|
|
, transit_stop_type("")
|
|
, transit_stop_offset(0.0f)
|
|
, transit_stop_dir_offset(0.0f)
|
|
, transit_stop_y_rotation(0.0f)
|
|
, sideroad(0)
|
|
, sideroad_offset(0.0f)
|
|
, sideroad_dir_offset(0.0f)
|
|
, sideroad_y_offset(0.0f)
|
|
, sideroad_y_rotation(0.0f)
|
|
, sideroad_type(String(""))
|
|
, lot(0)
|
|
, lot_offset(0.0f)
|
|
, lot_dir_offset(0.0f)
|
|
, lot_y_offset(0.0f)
|
|
, lot_y_rotation(0.0f)
|
|
, lot_type(String(""))
|
|
, lot_depth(100.0f)
|
|
, buildings{}
|
|
{
|
|
}
|
|
static void from_dict(struct road_edge_side &side,
|
|
const Dictionary &dict)
|
|
{
|
|
int i;
|
|
side.transit_stop_count = dict["transit_stop_count"];
|
|
side.transit_stop_type = dict["transit_stop_type"];
|
|
side.transit_stop_offset = dict["transit_stop_offset"];
|
|
side.transit_stop_dir_offset =
|
|
dict["transit_stop_dir_offset"];
|
|
side.transit_stop_y_rotation =
|
|
dict["transit_stop_y_rotation"];
|
|
side.sideroad = dict["sideroad"];
|
|
side.sideroad_offset = dict["sideroad_offset"];
|
|
side.sideroad_dir_offset = dict["sideroad_dir_offset"];
|
|
side.sideroad_y_offset = dict["sideroad_y_offset"];
|
|
side.sideroad_y_rotation = dict["sideroad_y_rotation"];
|
|
side.sideroad_type = dict["sideroad_type"];
|
|
side.lot = dict["lot"];
|
|
side.lot_depth = dict.get("lot_depth", 100.0f);
|
|
side.lot_offset = dict["lot_offset"];
|
|
side.lot_dir_offset = dict["lot_dir_offset"];
|
|
side.lot_y_offset = dict["lot_y_offset"];
|
|
side.lot_y_rotation = dict["lot_y_rotation"];
|
|
side.lot_type = dict["lot_type"];
|
|
String lot_buildings = dict["lot_buildings"];
|
|
lot_buildings = lot_buildings.strip_edges();
|
|
Vector<String> parts;
|
|
if (lot_buildings.find("!") >= 0)
|
|
parts = lot_buildings.split("!");
|
|
else
|
|
parts.push_back(lot_buildings);
|
|
side.buildings.resize(parts.size());
|
|
for (i = 0; i < parts.size(); i++) {
|
|
buildings::from_string(side.buildings[i],
|
|
parts[i]);
|
|
}
|
|
}
|
|
bool test(const struct RoadLinesData::test_edge &other);
|
|
void
|
|
update_test_points(const struct RoadLinesData::road_edge &edge);
|
|
struct RoadLinesData::road_edge_side &
|
|
operator=(const struct RoadLinesData::road_edge_side &other)
|
|
{
|
|
if (this == &other)
|
|
return *this;
|
|
from_dict(*this, other.to_dict());
|
|
pmid[0] = other.pmid[0];
|
|
pmid[1] = other.pmid[1];
|
|
pside[0] = other.pside[0];
|
|
pside[1] = other.pside[1];
|
|
normal = other.normal;
|
|
test_p[0] = other.test_p[0];
|
|
test_p[1] = other.test_p[1];
|
|
lot_depth_eff = other.lot_depth_eff;
|
|
lot_points = other.lot_points;
|
|
return *this;
|
|
}
|
|
};
|
|
struct test_edge {
|
|
String line_key;
|
|
int edge_index;
|
|
int p0_index, p1_index;
|
|
Vector3 p0, p1;
|
|
struct road_edge_side left, right;
|
|
test_edge(const String &key, int index)
|
|
: line_key(key)
|
|
, edge_index(index)
|
|
, left(RoadLinesData::get_singleton()->get_line_edge(
|
|
key, index))
|
|
, right(RoadLinesData::get_singleton()->get_line_edge(
|
|
key, index))
|
|
{
|
|
update_from_line();
|
|
}
|
|
bool operator==(const struct test_edge &other)
|
|
{
|
|
return line_key == other.line_key &&
|
|
edge_index == other.edge_index;
|
|
}
|
|
void validate()
|
|
{
|
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
|
RoadLinesData::road_edge edge =
|
|
rld->get_line_edge(line_key, edge_index);
|
|
if (edge.left.lot != left.lot) {
|
|
print_line("key: " + line_key +
|
|
" index: " + itos(edge_index));
|
|
print_line("rl.edges[edge_index].left.lot = " +
|
|
itos(edge.left.lot));
|
|
print_line("left.lot = " + itos(left.lot));
|
|
}
|
|
if (edge.right.lot != right.lot) {
|
|
print_line("key: " + line_key +
|
|
" index: " + itos(edge_index));
|
|
print_line("rl.edges[edge_index].right.lot = " +
|
|
itos(edge.right.lot));
|
|
print_line("right.lot = " + itos(right.lot));
|
|
}
|
|
assert(edge.left.lot == left.lot);
|
|
assert(edge.left.lot_depth == left.lot_depth);
|
|
assert(edge.right.lot == right.lot);
|
|
assert(edge.right.lot_depth == right.lot_depth);
|
|
}
|
|
void update_from_line()
|
|
{
|
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
|
RoadLinesData::road_edge edge =
|
|
rld->get_line_edge(line_key, edge_index);
|
|
print_line("line: " + line_key +
|
|
" index: " + itos(edge_index) +
|
|
" left.lot: " + itos(edge.left.lot) +
|
|
" right.lot: " + itos(edge.right.lot));
|
|
print_line(edge.left.pmid[0].operator String());
|
|
print_line(edge.right.pmid[0].operator String());
|
|
assert(edge.left.pmid[0].is_equal_approx(
|
|
edge.right.pmid[0]));
|
|
assert(edge.left.pmid[1].is_equal_approx(
|
|
edge.right.pmid[1]));
|
|
|
|
left = edge.left;
|
|
right = edge.right;
|
|
left.normal = edge.left.normal;
|
|
left.lot = edge.left.lot;
|
|
left.lot_depth = edge.left.lot_depth;
|
|
right.normal = edge.right.normal;
|
|
right.lot = edge.right.lot;
|
|
right.lot_depth = edge.right.lot_depth;
|
|
validate();
|
|
}
|
|
void update_line()
|
|
{
|
|
print_line("update_line");
|
|
RoadLinesData *rld = RoadLinesData::get_singleton();
|
|
RoadLinesData::road_edge_side tmp_left =
|
|
rld->get_line_edge_left(line_key, edge_index);
|
|
RoadLinesData::road_edge_side tmp_right =
|
|
rld->get_line_edge_right(line_key, edge_index);
|
|
tmp_left.lot = left.lot;
|
|
tmp_left.lot_depth = left.lot_depth;
|
|
tmp_right.lot = right.lot;
|
|
tmp_right.lot_depth = right.lot_depth;
|
|
rld->set_line_edge_left(line_key, edge_index, tmp_left);
|
|
rld->set_line_edge_right(line_key, edge_index,
|
|
tmp_right);
|
|
validate();
|
|
rld->update_line_edges();
|
|
validate();
|
|
}
|
|
};
|
|
struct road_edge {
|
|
struct road_edge_side left, right;
|
|
|
|
Dictionary to_dict() const
|
|
{
|
|
Dictionary ret;
|
|
ret["left"] = left.to_dict();
|
|
ret["right"] = right.to_dict();
|
|
return ret;
|
|
}
|
|
static void from_dict(struct road_edge &edge,
|
|
const Dictionary &dict)
|
|
{
|
|
const Dictionary &dleft = dict["left"],
|
|
&dright = dict["right"];
|
|
road_edge_side::from_dict(edge.left, dleft);
|
|
road_edge_side::from_dict(edge.right, dright);
|
|
}
|
|
road_edge()
|
|
: left(*this)
|
|
, right(*this)
|
|
{
|
|
}
|
|
};
|
|
struct road_line {
|
|
std::vector<Transform> points;
|
|
|
|
public:
|
|
std::vector<struct line_segment> segments;
|
|
int lanes;
|
|
int pattern;
|
|
int flags;
|
|
Dictionary metadata;
|
|
_Signal<void> line_updated;
|
|
};
|
|
struct road_line_index {
|
|
std::vector<int> indices;
|
|
};
|
|
void update_line_edges()
|
|
{
|
|
int edge_index;
|
|
List<String> keys;
|
|
get_road_lines_key_list(&keys);
|
|
List<String>::Element *e = keys.front();
|
|
while (e) {
|
|
String key = e->get();
|
|
// struct road_line rl = get_line(key);
|
|
for (edge_index = 0;
|
|
edge_index < get_line_edge_count(key);
|
|
edge_index++) {
|
|
const Vector3 &p0 =
|
|
get_line_point(key, edge_index);
|
|
const Vector3 &p1 =
|
|
get_line_point(key, edge_index + 1);
|
|
Vector3 dir = (p1 - p0).normalized();
|
|
Vector3 d = dir;
|
|
Vector3 left_n = Vector3(0, 1, 0).cross(d);
|
|
Vector3 right_n = -left_n;
|
|
RoadLinesData::road_edge tmp_edge =
|
|
get_line_edge(key, edge_index);
|
|
tmp_edge.left.normal = left_n;
|
|
tmp_edge.right.normal = right_n;
|
|
tmp_edge.left.pmid[0] = p0;
|
|
tmp_edge.left.pmid[1] = p1;
|
|
tmp_edge.right.pmid[0] = p0;
|
|
tmp_edge.right.pmid[1] = p1;
|
|
tmp_edge.left.test_p[0] = p0 + (p1 - p0) * 0.5f;
|
|
tmp_edge.left.test_p[1] =
|
|
tmp_edge.left.test_p[0] +
|
|
tmp_edge.left.normal *
|
|
tmp_edge.left.lot_depth;
|
|
tmp_edge.right.test_p[0] =
|
|
p0 + (p1 - p0) * 0.5f;
|
|
tmp_edge.right.test_p[1] =
|
|
tmp_edge.right.test_p[0] +
|
|
tmp_edge.right.normal *
|
|
tmp_edge.right.lot_depth;
|
|
set_line_edge(key, edge_index, tmp_edge);
|
|
}
|
|
e = e->next();
|
|
}
|
|
}
|
|
|
|
public:
|
|
static ImmediateGeometry *get_debug_node();
|
|
|
|
private:
|
|
HashMap<String, Ref<Curve3D> > curves;
|
|
|
|
public:
|
|
const struct road_line &get_line(const String &key) const;
|
|
const struct road_line &lines(const String &key) const;
|
|
const struct road_line_index &indices(const String &key) const;
|
|
void set_line(const String &key, const struct road_line &line);
|
|
void update_line(const String &key);
|
|
const struct road_line *get_line_ptr(const String &key) const;
|
|
const struct road_edge &get_line_edge(const String &key,
|
|
int edge) const;
|
|
struct road_edge_side get_line_edge_left(const String &key,
|
|
int edge) const;
|
|
struct road_edge_side get_line_edge_right(const String &key,
|
|
int edge) const;
|
|
struct road_edge_side get_line_edge_side(const String &key, int edge,
|
|
int side) const;
|
|
void set_line_edge_left(const String &key, int edge,
|
|
struct road_edge_side &side);
|
|
void set_line_edge_right(const String &key, int edge,
|
|
struct road_edge_side &side);
|
|
void set_line_edge(const String &key, int edge_id,
|
|
const struct road_edge &edge);
|
|
int get_line_edge_count(const String &key) const;
|
|
const Vector3 &get_line_point(const String &key, int index) const;
|
|
const Transform &get_line_point_transform(const String &key,
|
|
int index) const;
|
|
bool has_line(const String &key) const;
|
|
void insert_line_point(const String &key, int index,
|
|
const Transform &xform);
|
|
void erase_line_point(const String &key, int index);
|
|
void set_line_point_position(const String &key, int index,
|
|
const Vector3 &position);
|
|
void clear_all_line_indices();
|
|
void clear_line_indices(const String &key);
|
|
void set_line_metadata(const String &key, const Dictionary &metadata);
|
|
|
|
static RoadLinesData *get_singleton();
|
|
virtual ~RoadLinesData();
|
|
static void cleanup();
|
|
String get_road_lines_path();
|
|
void get_road_lines_key_list(List<String> *keys);
|
|
void get_lines_key_list(List<String> *keys);
|
|
const String &get_next_line(const String &key) const;
|
|
void erase_line(const String &key);
|
|
void load_data();
|
|
void save_data();
|
|
void process_lines(std::unordered_map<uint32_t, std::vector<Vector3> >
|
|
&road_lines_nodes_hash,
|
|
std::vector<Vector3> &road_lines_nodes);
|
|
void set_debug_flags(int debug_flags);
|
|
int get_debug_flags() const;
|
|
void update_line_segments(const String &line);
|
|
Vector3 get_point_by_offsets(const String &line, float dir_offset,
|
|
float normal_offset);
|
|
|
|
private:
|
|
void create_segments_from_lines();
|
|
void index_lines(std::unordered_map<uint32_t, std::vector<Vector3> >
|
|
&road_lines_nodes_hash,
|
|
std::vector<Vector3> &road_lines_nodes);
|
|
|
|
void create_segments(const String &road, std::vector<int> &segments);
|
|
void insert_close_points(std::vector<Vector3> &road_lines_nodes,
|
|
float distance_squared);
|
|
|
|
void update_road_lines_nodes(std::vector<Vector3> &road_lines_nodes);
|
|
|
|
void dump_road_lines(const std::vector<Vector3> &road_lines_nodes);
|
|
void road_lines_curve_index(
|
|
const String &key,
|
|
std::unordered_map<uint32_t, std::vector<Vector3> >
|
|
&road_lines_nodes_hash,
|
|
std::vector<Vector3> &road_lines_nodes);
|
|
};
|
|
#endif |