#ifndef ROAD_LINES_DATA_H #define ROAD_LINES_DATA_H #include #include #include #include #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 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 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 parts = data.split(":"); if (parts.size() < 3) return; assert(parts.size() == 3); Vector 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 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 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 points; public: std::vector segments; int lanes; int pattern; int flags; Dictionary metadata; _Signal line_updated; }; struct road_line_index { std::vector indices; }; void update_line_edges() { int edge_index; List keys; get_road_lines_key_list(&keys); List::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 > 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 *keys); void get_lines_key_list(List *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 > &road_lines_nodes_hash, std::vector &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 > &road_lines_nodes_hash, std::vector &road_lines_nodes); void create_segments(const String &road, std::vector &segments); void insert_close_points(std::vector &road_lines_nodes, float distance_squared); void update_road_lines_nodes(std::vector &road_lines_nodes); void dump_road_lines(const std::vector &road_lines_nodes); void road_lines_curve_index( const String &key, std::unordered_map > &road_lines_nodes_hash, std::vector &road_lines_nodes); }; #endif