Spaces:
Sleeping
Sleeping
| using std::map; | |
| using std::string; | |
| namespace CityFlow { | |
| static double getLengthOfPoints(const std::vector<Point> &points); | |
| static Point getPointByDistance(const std::vector<Point> &points, double dis) { | |
| dis = min2double(max2double(dis, 0), getLengthOfPoints(points)); | |
| if (dis <= 0.0) | |
| return points[0]; | |
| for (size_t i = 1; i < points.size(); i++) { | |
| double len = (points[i - 1] - points[i]).len(); | |
| if (dis > len) | |
| dis -= len; | |
| else | |
| return points[i - 1] + (points[i] - points[i - 1]) * (dis / len); | |
| } | |
| return points.back(); | |
| } | |
| static double getLengthOfPoints(const std::vector<Point> &points) { | |
| double length = 0.0; | |
| for (size_t i = 0; i + 1 < points.size(); i++) | |
| length += (points[i + 1] - points[i]).len(); | |
| return length; | |
| } | |
| Point RoadNet::getPoint(const Point &p1, const Point &p2, double a) { | |
| return Point((p2.x - p1.x) * a + p1.x, (p2.y - p1.y) * a + p1.y); | |
| } | |
| bool RoadNet::loadFromJson(std::string jsonFileName) { | |
| rapidjson::Document document; | |
| if (!readJsonFromFile(jsonFileName, document)) { | |
| std::cerr << "cannot open roadnet file" << std::endl; | |
| return false; | |
| } | |
| //std::clog << root << std::endl; | |
| std::list<std::string> path; | |
| if (!document.IsObject()) | |
| throw JsonTypeError("roadnet config file", "object"); | |
| try { | |
| const rapidjson::Value &interValues = getJsonMemberArray("intersections", document); | |
| const rapidjson::Value &roadValues = getJsonMemberArray("roads", document); | |
| // build mapping | |
| roads.resize(roadValues.Size()); | |
| intersections.resize(interValues.Size()); | |
| for (rapidjson::SizeType i = 0; i < roadValues.Size(); i++) { | |
| path.emplace_back("road[" + std::to_string(i) + "]"); | |
| std::string id = getJsonMember<const char*>("id", roadValues[i]); | |
| roadMap[id] = &roads[i]; | |
| roads[i].id = id; | |
| path.pop_back(); | |
| } | |
| assert(path.empty()); | |
| for (rapidjson::SizeType i = 0; i < interValues.Size(); i++) { | |
| path.emplace_back("intersection[" + std::to_string(i) + "]"); | |
| std::string id = getJsonMember<const char*>("id", interValues[i]);; | |
| interMap[id] = &intersections[i]; | |
| intersections[i].id = id; | |
| path.pop_back(); | |
| } | |
| assert(path.empty()); | |
| // read roads | |
| path.emplace_back("roads"); | |
| for (rapidjson::SizeType i = 0; i < roadValues.Size(); i++) { | |
| // read startIntersection, endIntersection | |
| path.emplace_back(roads[i].getId()); | |
| const auto &curRoadValue = roadValues[i]; | |
| if (!curRoadValue.IsObject()) { | |
| throw JsonTypeError("road[" + std::to_string(i) + "]", "object"); | |
| } | |
| roads[i].startIntersection = interMap[getJsonMember<const char*>("startIntersection", curRoadValue)]; | |
| roads[i].endIntersection = interMap[getJsonMember<const char*>("endIntersection", curRoadValue)]; | |
| // Check | |
| if (!roads[i].startIntersection) throw JsonFormatError("startIntersection does not exist."); | |
| if (!roads[i].endIntersection) throw JsonFormatError("endIntersection does not exist."); | |
| // read lanes | |
| const auto &lanesValue = getJsonMemberArray("lanes", curRoadValue); | |
| int laneIndex = 0; | |
| for (const auto &laneValue : lanesValue.GetArray()) { | |
| path.emplace_back("lane[" + std::to_string(laneIndex) + "]"); | |
| if (!laneValue.IsObject()) | |
| throw JsonTypeError("lane", "object"); | |
| double width = getJsonMember<double>("width", laneValue); | |
| double maxSpeed = getJsonMember<double>("maxSpeed", laneValue); | |
| roads[i].lanes.emplace_back(width, maxSpeed, laneIndex, &roads[i]); | |
| laneIndex++; | |
| path.pop_back(); | |
| } | |
| for (auto &lane : roads[i].lanes) { | |
| drivableMap[lane.getId()] = &lane; | |
| } | |
| // read points | |
| const auto &pointsValue = getJsonMemberArray("points", curRoadValue); | |
| for (const auto &pointValue : pointsValue.GetArray()) { | |
| path.emplace_back("point[" + std::to_string(roads[i].points.size()) + "]"); | |
| if (!pointValue.IsObject()) | |
| throw JsonTypeError("point of road", "object"); | |
| double x = getJsonMember<double>("x", pointValue); | |
| double y = getJsonMember<double>("y", pointValue); | |
| roads[i].points.emplace_back(x, y); | |
| path.pop_back(); | |
| } | |
| path.pop_back(); | |
| } | |
| path.pop_back(); | |
| assert(path.empty()); | |
| for (rapidjson::SizeType i = 0; i < roadValues.Size(); i++) { | |
| roads[i].initLanesPoints(); | |
| } | |
| // read intersections | |
| std::map<std::string, RoadLinkType> typeMap = {{"turn_left", turn_left}, | |
| {"turn_right", turn_right}, | |
| {"go_straight", go_straight}}; | |
| path.emplace_back("intersections"); | |
| for (rapidjson::SizeType i = 0; i < interValues.Size(); i++) { | |
| path.emplace_back(intersections[i].getId()); | |
| const auto &curInterValue = interValues[i]; | |
| if (!curInterValue.IsObject()) { | |
| throw JsonTypeError("intersection", "object"); | |
| return false; | |
| } | |
| // read point | |
| const auto &pointValue = getJsonMemberObject("point", curInterValue); | |
| intersections[i].isVirtual = getJsonMember<bool>("virtual", curInterValue); | |
| double x = getJsonMember<double>("x", pointValue); | |
| double y = getJsonMember<double>("y", pointValue); | |
| intersections[i].point = Point(x, y); | |
| // read roads | |
| const auto &roadsValue = getJsonMemberArray("roads", curInterValue); | |
| for (auto &roadNameValue : roadsValue.GetArray()) { | |
| path.emplace_back("roads[" + std::to_string(intersections[i].roads.size()) + "]"); | |
| std::string roadName = roadNameValue.GetString(); | |
| if (!roadMap.count(roadName)) | |
| throw JsonFormatError("No such road: " + roadName); | |
| intersections[i].roads.push_back(roadMap[roadName]); | |
| path.pop_back(); | |
| } | |
| // skip other information if intersection is virtual | |
| intersections[i].trafficLight.intersection = &intersections[i]; | |
| if (intersections[i].isVirtual) { | |
| path.pop_back(); | |
| continue; | |
| } | |
| // read width | |
| intersections[i].width = getJsonMember<double>("width", curInterValue); | |
| // read laneLinks | |
| const auto &roadLinksValue = getJsonMemberArray("roadLinks", curInterValue); | |
| intersections[i].roadLinks.resize(roadLinksValue.Size()); | |
| int roadLinkIndex = 0; | |
| for (const auto &roadLinkValue : roadLinksValue.GetArray()) { | |
| path.emplace_back("roadLinks[" + std::to_string(roadLinkIndex) + "]"); | |
| if (!roadLinkValue.IsObject()) | |
| throw JsonTypeError("roadLink", "object"); | |
| RoadLink &roadLink = intersections[i].roadLinks[roadLinkIndex]; | |
| roadLink.index = roadLinkIndex++; | |
| roadLink.type = typeMap[getJsonMember<const char*>("type", roadLinkValue)]; | |
| roadLink.startRoad = roadMap[getJsonMember<const char*>("startRoad", roadLinkValue)]; | |
| roadLink.endRoad = roadMap[getJsonMember<const char*>("endRoad", roadLinkValue)]; | |
| const auto &laneLinksValue = getJsonMemberArray("laneLinks", roadLinkValue); | |
| roadLink.laneLinks.resize(laneLinksValue.Size()); | |
| int laneLinkIndex = 0; | |
| for (const auto &laneLinkValue : laneLinksValue.GetArray()) { | |
| path.emplace_back("laneLinks[" + std::to_string(laneLinkIndex) + "]"); | |
| if (!laneLinkValue.IsObject()) | |
| throw JsonTypeError("laneLink", "object"); | |
| LaneLink &laneLink = roadLink.laneLinks[laneLinkIndex++]; | |
| int startLaneIndex = getJsonMember<int>("startLaneIndex", laneLinkValue); | |
| int endLaneIndex = getJsonMember<int>("endLaneIndex", laneLinkValue); | |
| if (startLaneIndex >= static_cast<int>(roadLink.startRoad->lanes.size()) || startLaneIndex < 0) | |
| throw JsonFormatError("startLaneIndex out of range"); | |
| if (endLaneIndex >= static_cast<int>(roadLink.endRoad->lanes.size()) || endLaneIndex < 0) | |
| throw JsonFormatError("startLaneIndex out of range"); | |
| Lane *startLane = &roadLink.startRoad->lanes[startLaneIndex]; | |
| Lane *endLane = &roadLink.endRoad->lanes[endLaneIndex]; | |
| auto iter = laneLinkValue.FindMember("points"); | |
| if (iter != laneLinkValue.MemberEnd() && !iter->value.IsArray()) | |
| throw JsonTypeError("points in laneLink", "array"); | |
| if (iter != laneLinkValue.MemberEnd() && !iter->value.Empty()) | |
| for (const auto &pValue : iter->value.GetArray()) { | |
| laneLink.points.emplace_back(getJsonMember<double>("x", pValue), | |
| getJsonMember<double>("y", pValue)); | |
| } | |
| else { | |
| Point start = Point(startLane->getPointByDistance( | |
| startLane->getLength() - startLane->getEndIntersection()->width)); | |
| Point end = Point( | |
| endLane->getPointByDistance(0.0 + endLane->getStartIntersection()->width)); | |
| double len = (Point(end.x - start.x, end.y - start.y)).len(); | |
| Point startDirection = startLane->getDirectionByDistance( | |
| startLane->getLength() - startLane->getEndIntersection()->width); | |
| Point endDirection = endLane->getDirectionByDistance( | |
| 0.0 + endLane->getStartIntersection()->width); | |
| double minGap = 5; | |
| double gap1X = startDirection.x * len * 0.5; | |
| double gap1Y = startDirection.y * len * 0.5; | |
| double gap2X = -endDirection.x * len * 0.5; | |
| double gap2Y = -endDirection.y * len * 0.5; | |
| if (gap1X * gap1X + gap1Y * gap1Y < 25 && startLane->getEndIntersection()->width >= 5) { | |
| gap1X = minGap * startDirection.x; | |
| gap1Y = minGap * startDirection.y; | |
| } | |
| if (gap2X * gap2X + gap2Y * gap2Y < 25 && endLane->getStartIntersection()->width >= 5) { | |
| gap2X = minGap * endDirection.x; | |
| gap2Y = minGap * endDirection.y; | |
| } | |
| Point mid1 = Point(start.x + gap1X,start.y + gap1Y); | |
| Point mid2 = Point(end.x + gap2X,end.y + gap2Y); | |
| int numPoints = 10; | |
| for (int i = 0; i <= numPoints; i++) { | |
| Point p1 = getPoint(start, mid1, i / double(numPoints)); | |
| Point p2 = getPoint(mid1, mid2, i / double(numPoints)); | |
| Point p3 = getPoint(mid2, end, i / double(numPoints)); | |
| Point p4 = getPoint(p1, p2, i / double(numPoints)); | |
| Point p5 = getPoint(p2, p3, i / double(numPoints)); | |
| Point p6 = getPoint(p4, p5, i / double(numPoints)); | |
| laneLink.points.emplace_back(p6.x, p6.y); | |
| } | |
| } | |
| laneLink.roadLink = &roadLink; | |
| laneLink.startLane = startLane; | |
| laneLink.endLane = endLane; | |
| laneLink.length = getLengthOfPoints(laneLink.points); | |
| startLane->laneLinks.push_back(&laneLink); | |
| drivableMap.emplace(laneLink.getId(), &laneLink); | |
| path.pop_back(); | |
| } | |
| roadLink.intersection = &intersections[i]; | |
| path.pop_back(); | |
| } | |
| // read trafficLight | |
| const auto &trafficLightValue = getJsonMemberObject("trafficLight", curInterValue); | |
| path.emplace_back("trafficLight"); | |
| const auto &lightPhasesValue = getJsonMemberArray("lightphases", trafficLightValue); | |
| for (const auto &lightPhaseValue : lightPhasesValue.GetArray()) { | |
| path.emplace_back("lightphases[" + std::to_string(intersections[i].trafficLight.phases.size()) + "]"); | |
| if (!lightPhaseValue.IsObject()) | |
| throw JsonTypeError("lightphase", "object"); | |
| LightPhase lightPhase; | |
| lightPhase.time = getJsonMember<double>("time", lightPhaseValue); | |
| lightPhase.roadLinkAvailable = std::vector<bool>(intersections[i].roadLinks.size(), false); | |
| const auto& availableRoadLinksValue = | |
| getJsonMemberArray("availableRoadLinks", lightPhaseValue); | |
| for (rapidjson::SizeType index = 0; index < availableRoadLinksValue.Size(); index++) { | |
| path.emplace_back("availableRoadLinks[" + std::to_string(index) + "]"); | |
| if (!availableRoadLinksValue[index].IsInt()) | |
| throw JsonTypeError("availableRoadLink", "int"); | |
| size_t indexInRoadLinks = availableRoadLinksValue[index].GetUint(); | |
| if (indexInRoadLinks >= lightPhase.roadLinkAvailable.size()) | |
| throw JsonFormatError("index out of range"); | |
| lightPhase.roadLinkAvailable[indexInRoadLinks] = true; | |
| path.pop_back(); | |
| } | |
| intersections[i].trafficLight.phases.push_back(lightPhase); | |
| path.pop_back(); | |
| } | |
| path.pop_back(); // End of traffic light | |
| intersections[i].trafficLight.init(0); | |
| path.pop_back(); // End of intersection | |
| } | |
| path.pop_back(); | |
| assert(path.empty()); | |
| }catch (const JsonFormatError &e) { | |
| std::cerr << "Error occurred when reading the roadnet file: " << std::endl; | |
| for (const auto &node : path) { | |
| std::cerr << "/" << node; | |
| } | |
| std::cerr << " " << e.what() << std::endl; | |
| return false; | |
| } | |
| for (auto &intersection : intersections) | |
| intersection.initCrosses(); | |
| VehicleInfo vehicleTemplate; | |
| for (auto &road : roads) | |
| road.initLanesPoints(); | |
| for (auto &road : roads) { | |
| road.buildSegmentationByInterval((vehicleTemplate.len + vehicleTemplate.minGap) * MAX_NUM_CARS_ON_SEGMENT); | |
| } | |
| for (auto &road : roads) { | |
| auto &roadLanes = road.getLanePointers(); | |
| lanes.insert(lanes.end(), roadLanes.begin(), roadLanes.end()); | |
| drivables.insert(drivables.end(), roadLanes.begin(), roadLanes.end()); | |
| } | |
| for (auto &intersection : intersections) { | |
| auto &intersectionLaneLinks = intersection.getLaneLinks(); | |
| laneLinks.insert(laneLinks.end(), intersectionLaneLinks.begin(), intersectionLaneLinks.end()); | |
| drivables.insert(drivables.end(), intersectionLaneLinks.begin(), intersectionLaneLinks.end()); | |
| } | |
| return true; | |
| } | |
| rapidjson::Value RoadNet::convertToJson(rapidjson::Document::AllocatorType &allocator) { | |
| rapidjson::Value jsonRoot(rapidjson::kObjectType); | |
| // write nodes | |
| rapidjson::Value jsonNodes(rapidjson::kArrayType); | |
| for (size_t i = 0; i < intersections.size(); ++i) { | |
| rapidjson::Value jsonNode(rapidjson::kObjectType), jsonPoint(rapidjson::kArrayType); | |
| rapidjson::Value idValue; | |
| idValue.SetString(rapidjson::StringRef(intersections[i].id.c_str())); | |
| jsonNode.AddMember("id", idValue, allocator); | |
| jsonPoint.PushBack(intersections[i].point.x, allocator); | |
| jsonPoint.PushBack(intersections[i].point.y, allocator); | |
| jsonNode.AddMember("point", jsonPoint, allocator); | |
| jsonNode.AddMember("virtual", intersections[i].isVirtual, allocator); | |
| if (!intersections[i].isVirtual) { | |
| jsonNode.AddMember("width", intersections[i].width, allocator); | |
| } | |
| rapidjson::Value jsonOutline(rapidjson::kArrayType); | |
| for (auto &point: intersections[i].getOutline()) { | |
| jsonOutline.PushBack(point.x, allocator); | |
| jsonOutline.PushBack(point.y, allocator); | |
| } | |
| jsonNode.AddMember("outline", jsonOutline, allocator); | |
| jsonNodes.PushBack(jsonNode, allocator); | |
| } | |
| jsonRoot.AddMember("nodes", jsonNodes, allocator); | |
| //write edges | |
| rapidjson::Value jsonEdges(rapidjson::kArrayType); | |
| for (size_t i = 0; i < roads.size(); ++i) { | |
| rapidjson::Value jsonEdge(rapidjson::kObjectType); | |
| rapidjson::Value jsonPoints(rapidjson::kArrayType); | |
| rapidjson::Value jsonLaneWidths(rapidjson::kArrayType); | |
| rapidjson::Value jsonDirs(rapidjson::kArrayType); | |
| rapidjson::Value idValue; | |
| idValue.SetString(rapidjson::StringRef(roads[i].id.c_str())); | |
| jsonEdge.AddMember("id", idValue, allocator); | |
| rapidjson::Value startValue; | |
| if (roads[i].startIntersection) | |
| startValue.SetString(rapidjson::StringRef(roads[i].startIntersection->id.c_str())); | |
| else | |
| startValue.SetString("null"); | |
| jsonEdge.AddMember("from", startValue, allocator); | |
| rapidjson::Value endValue; | |
| if (roads[i].endIntersection) | |
| endValue.SetString(rapidjson::StringRef(roads[i].endIntersection->id.c_str())); | |
| else | |
| endValue.SetString("null"); | |
| jsonEdge.AddMember("to", endValue, allocator); | |
| for (size_t j = 0; j < roads[i].points.size(); ++j) { | |
| rapidjson::Value jsonPoint(rapidjson::kArrayType); | |
| jsonPoint.PushBack(roads[i].points[j].x, allocator); | |
| jsonPoint.PushBack(roads[i].points[j].y, allocator); | |
| jsonPoints.PushBack(jsonPoint, allocator); | |
| } | |
| jsonEdge.AddMember("points", jsonPoints, allocator); | |
| jsonEdge.AddMember("nLane", static_cast<int>(roads[i].lanes.size()), allocator); | |
| for (size_t j = 0; j < roads[i].lanes.size(); ++j) { | |
| jsonLaneWidths.PushBack(roads[i].lanes[j].width, allocator); | |
| } | |
| jsonEdge.AddMember("laneWidths", jsonLaneWidths, allocator); | |
| jsonEdges.PushBack(jsonEdge, allocator); | |
| } | |
| jsonRoot.AddMember("edges", jsonEdges, allocator); | |
| return jsonRoot; | |
| } | |
| Point Drivable::getPointByDistance(double dis) const { | |
| return CityFlow::getPointByDistance(points, dis); | |
| } | |
| Point Drivable::getDirectionByDistance(double dis) const { | |
| double remain = dis; | |
| for (int i = 0; i + 1 < (int) points.size(); i++) { | |
| double len = (points[i + 1] - points[i]).len(); | |
| if (remain < len) | |
| return (points[i + 1] - points[i]).unit(); | |
| else | |
| remain -= len; | |
| } | |
| return (points[points.size() - 1] - points[points.size() - 2]).unit(); | |
| } | |
| Lane::Lane() { | |
| width = 0; | |
| maxSpeed = 0; | |
| laneIndex = -1; | |
| belongRoad = 0; | |
| drivableType = LANE; | |
| } | |
| Lane::Lane(double width, double maxSpeed, int laneIndex, Road *belongRoad) { | |
| this->width = width; | |
| this->maxSpeed = maxSpeed; | |
| this->laneIndex = laneIndex; | |
| this->belongRoad = belongRoad; | |
| drivableType = LANE; | |
| } | |
| bool Lane::available(const Vehicle *vehicle) const { | |
| if (!vehicles.empty()) { | |
| Vehicle *tail = vehicles.back(); | |
| return tail->getDistance() > tail->getLen() + vehicle->getMinGap(); | |
| } else { | |
| return true; | |
| } | |
| } | |
| bool Lane::canEnter(const Vehicle *vehicle) const { | |
| if (!vehicles.empty()) { | |
| Vehicle *tail = vehicles.back(); | |
| return tail->getDistance() > tail->getLen() + vehicle->getLen() || | |
| tail->getSpeed() >= 2; //todo: speed > 2 or? | |
| } else { | |
| return true; | |
| } | |
| } | |
| std::vector<LaneLink *> Lane::getLaneLinksToRoad(const Road *road) const { | |
| std::vector<LaneLink *> ret; | |
| for (auto &laneLink : laneLinks) { | |
| if (laneLink->getEndLane()->getBelongRoad() == road) | |
| ret.push_back(laneLink); | |
| } | |
| return ret; | |
| } | |
| void Road::initLanesPoints() { | |
| double dsum = 0.0; | |
| std::vector<Point> roadPoints = this->points; | |
| assert(roadPoints.size() >= 2); | |
| if (!startIntersection->isVirtualIntersection()) { | |
| double width = startIntersection->width; | |
| Point p1 = roadPoints[0]; | |
| Point p2 = roadPoints[1]; | |
| roadPoints[0] = p1 + (p2 - p1).unit() * width; | |
| } | |
| if (!endIntersection->isVirtualIntersection()) { | |
| double width = endIntersection->width; | |
| Point p1 = roadPoints[roadPoints.size() - 2]; | |
| Point p2 = roadPoints[roadPoints.size() - 1]; | |
| roadPoints[roadPoints.size() - 1] = p2 - (p2 - p1).unit() * width; | |
| } | |
| for (Lane &lane : lanes) { | |
| double dmin = dsum; | |
| double dmax = dsum + lane.width; | |
| lane.points.clear(); | |
| for (int j = 0; j < (int) roadPoints.size(); j++) { | |
| // TODO: the '(dmin + dmax) / 2.0' is wrong | |
| std::vector<Point> &lanePoints = lane.points; | |
| if (j == 0) { | |
| Vector u = (roadPoints[1] - roadPoints[0]).unit(); | |
| Vector v = -u.normal(); | |
| Point startPoint = roadPoints[j] + v * ((dmin + dmax) / 2.0); | |
| lanePoints.push_back(startPoint); | |
| } else if (j + 1 == (int) roadPoints.size()) { | |
| Vector u = (roadPoints[j] - roadPoints[j - 1]).unit(); | |
| Vector v = -u.normal(); | |
| Point endPoint = roadPoints[j] + v * ((dmin + dmax) / 2.0); | |
| lanePoints.push_back(endPoint); | |
| } else { | |
| Vector u1 = (roadPoints[j + 1] - roadPoints[j]).unit(); | |
| Vector u2 = (roadPoints[j] - roadPoints[j - 1]).unit(); | |
| Vector u = (u1 + u2).unit(); | |
| Vector v = -u.normal(); | |
| Point interPoint = roadPoints[j] + v * ((dmin + dmax) / 2.0); | |
| lanePoints.push_back(interPoint); | |
| } | |
| } | |
| lane.length = getLengthOfPoints(lane.points); | |
| dsum += lane.width; | |
| } | |
| } | |
| const std::vector<Lane *> &Road::getLanePointers() { | |
| if (lanePointers.size()) return lanePointers; | |
| for (auto &lane : lanes) { | |
| lanePointers.push_back(&lane); | |
| } | |
| return lanePointers; | |
| } | |
| void Intersection::initCrosses() { | |
| std::vector<LaneLink *> allLaneLinks; | |
| for (auto &roadLink : roadLinks) { | |
| for (auto &laneLink : roadLink.getLaneLinks()) | |
| allLaneLinks.push_back(&laneLink); | |
| } | |
| int n = (int) allLaneLinks.size(); | |
| for (int i = 0; i < n; i++) { | |
| for (int j = i + 1; j < n; j++) { | |
| LaneLink *la = allLaneLinks[i]; | |
| LaneLink *lb = allLaneLinks[j]; | |
| std::vector<Point> &va = la->points; | |
| std::vector<Point> &vb = lb->points; | |
| double disa = 0.0; | |
| for (int ia = 0; ia + 1 < (int) va.size(); ia++) { | |
| double disb = 0.0; | |
| for (int ib = 0; ib + 1 < (int) vb.size(); ib++) { | |
| Point A1 = va[ia], A2 = va[ia + 1]; | |
| Point B1 = vb[ib], B2 = vb[ib + 1]; | |
| if (Point::sign(crossMultiply(A2 - A1, B2 - B1)) == 0) continue; | |
| Point P = calcIntersectPoint(A1, A2, B1, B2); | |
| if (onSegment(A1, A2, P) && onSegment(B1, B2, P)) { | |
| Cross cross; | |
| cross.laneLinks[0] = la; | |
| cross.laneLinks[1] = lb; | |
| cross.notifyVehicles[0] = nullptr; | |
| cross.notifyVehicles[1] = nullptr; | |
| cross.distanceOnLane[0] = disa + (P - A1).len(); | |
| cross.distanceOnLane[1] = disb + (P - B1).len(); | |
| cross.ang = calcAng(A2 - A1, B2 - B1); | |
| //assert(cross.ang > 0 && cross.ang < M_PI / 2); // assert cannot pass why? | |
| double w1 = la->getWidth(); | |
| double w2 = lb->getWidth(); | |
| double c1 = w1 / sin(cross.ang); | |
| double c2 = w2 / sin(cross.ang); | |
| double diag = (c1 * c1 + c2 * c2 + 2 * c1 * c2 * cos(cross.ang)) / 4; | |
| cross.safeDistances[0] = sqrt(diag - w2 * w2 / 4); | |
| cross.safeDistances[1] = sqrt(diag - w1 * w1 / 4); | |
| this->crosses.push_back(cross); | |
| goto FOUND; | |
| } | |
| disb += (vb[ib + 1] - vb[ib]).len(); | |
| } | |
| disa += (va[ia + 1] - va[ia]).len(); | |
| } | |
| FOUND:; | |
| } | |
| } | |
| for (Cross &cross : this->crosses) { | |
| cross.laneLinks[0]->getCrosses().push_back(&cross); | |
| cross.laneLinks[1]->getCrosses().push_back(&cross); | |
| } | |
| for (auto laneLink : allLaneLinks) { | |
| std::vector<Cross *> &crosses = laneLink->getCrosses(); | |
| sort(crosses.begin(), crosses.end(), [laneLink](Cross *ca, Cross *cb) -> bool { | |
| double da = ca->distanceOnLane[ca->laneLinks[0] != laneLink]; | |
| double db = cb->distanceOnLane[cb->laneLinks[0] != laneLink]; | |
| return da < db; | |
| }); | |
| } | |
| } | |
| const std::vector<LaneLink *> &Intersection::getLaneLinks() { | |
| if (laneLinks.size() > 0) return laneLinks; | |
| for (auto &roadLink : roadLinks) { | |
| auto &roadLaneLinks = roadLink.getLaneLinkPointers(); | |
| laneLinks.insert(laneLinks.end(), roadLaneLinks.begin(), roadLaneLinks.end()); | |
| } | |
| return laneLinks; | |
| } | |
| const std::vector<LaneLink *> &RoadLink::getLaneLinkPointers() { | |
| if (laneLinkPointers.size() > 0) return laneLinkPointers; | |
| for (auto &laneLink : laneLinks) { | |
| laneLinkPointers.push_back(&laneLink); | |
| } | |
| return laneLinkPointers; | |
| } | |
| void Cross::notify(LaneLink *laneLink, Vehicle *vehicle, double notifyDistance) { | |
| assert(laneLink == laneLinks[0] || laneLink == laneLinks[1]); | |
| int i = (laneLink == laneLinks[0]) ? 0 : 1; | |
| assert(notifyVehicles[i] == nullptr); | |
| notifyVehicles[i] = vehicle; | |
| notifyDistances[i] = notifyDistance; | |
| } | |
| bool Cross::canPass(const Vehicle *vehicle, const LaneLink *laneLink, double distanceToLaneLinkStart) const { | |
| // TODO: should be improved | |
| assert(laneLink == laneLinks[0] || laneLink == laneLinks[1]); | |
| int i = (laneLink == laneLinks[0]) ? 0 : 1; | |
| Vehicle *foeVehicle = notifyVehicles[1 - i]; | |
| RoadLinkType t1 = laneLinks[i]->getRoadLinkType(); | |
| RoadLinkType t2 = laneLinks[1 - i]->getRoadLinkType(); | |
| double d1 = distanceOnLane[i] - distanceToLaneLinkStart, d2 = notifyDistances[1 - i]; | |
| if (foeVehicle == nullptr) return true; | |
| if (!vehicle->canYield(d1)) return true; | |
| int yield = 0; | |
| if (!foeVehicle->canYield(d2)) yield = 1; | |
| if (yield == 0) { | |
| if (t1 > t2) { | |
| yield = -1; | |
| } else if (t1 < t2) { | |
| if (d2 > 0) { | |
| // todo: can be improved, check if higher priority vehicle is blocked by other vehicles, hard! | |
| int foeVehicleReachSteps = foeVehicle->getReachStepsOnLaneLink(d2, laneLinks[1 - i]); | |
| int reachSteps = vehicle->getReachStepsOnLaneLink(d1, laneLinks[i]); | |
| if (foeVehicleReachSteps > reachSteps) { | |
| yield = -1; | |
| } | |
| } else { | |
| if (d2 + foeVehicle->getLen() < 0) { | |
| yield = -1; | |
| } | |
| } | |
| if (yield == 0) yield = 1; | |
| } else { | |
| if (d2 > 0) { | |
| int foeVehicleReachSteps = foeVehicle->getReachStepsOnLaneLink(d2, laneLinks[1 - i]); | |
| int reachSteps = vehicle->getReachStepsOnLaneLink(d1, laneLinks[i]); | |
| if (foeVehicleReachSteps > reachSteps) { | |
| yield = -1; | |
| } else if (foeVehicleReachSteps < reachSteps) { | |
| yield = 1; | |
| } else { | |
| if (vehicle->getEnterLaneLinkTime() == foeVehicle->getEnterLaneLinkTime()) { | |
| if (d1 == d2) { | |
| yield = vehicle->getPriority() > foeVehicle->getPriority() ? -1 : 1; | |
| } else { | |
| yield = d1 < d2 ? -1 : 1; | |
| } | |
| } else { | |
| yield = vehicle->getEnterLaneLinkTime() < foeVehicle->getEnterLaneLinkTime() ? -1 : 1; | |
| } | |
| } | |
| } else { | |
| yield = d2 + foeVehicle->getLen() < 0 ? -1 : 1; | |
| } | |
| } | |
| } | |
| assert(yield != 0); | |
| if (yield == 1) { | |
| Vehicle *fastPointer = foeVehicle; | |
| Vehicle *slowPointer = foeVehicle; | |
| while (fastPointer != nullptr && fastPointer->getBlocker() != nullptr) { | |
| slowPointer = slowPointer->getBlocker(); | |
| fastPointer = fastPointer->getBlocker()->getBlocker(); | |
| if (slowPointer == fastPointer) { | |
| // deadlock detected | |
| yield = -1; | |
| break; | |
| } | |
| } | |
| } | |
| return yield == -1; | |
| } | |
| void RoadNet::reset() { | |
| for (auto &road : roads) road.reset(); | |
| for (auto &intersection : intersections) intersection.reset(); | |
| } | |
| void Road::reset() { | |
| for (auto &lane : lanes) lane.reset(); | |
| } | |
| void Road::buildSegmentationByInterval(double interval) { | |
| size_t numSegs = std::max((size_t) ceil(getLengthOfPoints(this->points) / interval), (size_t) 1); | |
| for (Lane &lane : lanes) | |
| lane.buildSegmentation(numSegs); | |
| } | |
| double Road::getWidth() const{ | |
| double width = 0; | |
| for (const auto &lane : getLanes()){ | |
| width += lane.getWidth(); | |
| } | |
| return width; | |
| } | |
| double Road::getLength() const{ | |
| double length = 0; | |
| for (const auto &lane : getLanes()){ | |
| length += lane.getLength(); | |
| } | |
| return length; | |
| } | |
| double Road::averageLength() const{ | |
| double sum = 0; | |
| size_t laneNum = getLanes().size(); | |
| if (laneNum == 0) return 0; | |
| for (const auto &lane : getLanes()){ | |
| sum += lane.getLength(); | |
| } | |
| return sum / laneNum; | |
| } | |
| double Road::getAverageSpeed() const{ | |
| int vehicleNum = 0; | |
| double speedSum = 0; | |
| for (const auto &lane : lanes) { | |
| vehicleNum += lane.getHistoryVehicleNum(); | |
| speedSum += lane.getHistoryAverageSpeed() * lane.getHistoryVehicleNum(); | |
| } | |
| return vehicleNum ? speedSum / vehicleNum : -1; | |
| // If no vehicles in history, return -1 | |
| } | |
| double Road::getAverageDuration() const{ | |
| double averageSpeed = getAverageSpeed(); | |
| if (averageSpeed < 0) return -1; | |
| return averageLength() / averageSpeed; | |
| } | |
| bool Road::connectedToRoad(const Road *road) const{ | |
| for (const auto &lane : getLanes()) { | |
| if (lane.getLaneLinksToRoad(road).size()) | |
| return true; | |
| } | |
| return false; | |
| } | |
| void Intersection::reset() { | |
| trafficLight.reset(); | |
| for (auto &roadLink : roadLinks) roadLink.reset(); | |
| for (auto &cross : crosses) cross.reset(); | |
| } | |
| std::vector<Point> Intersection::getOutline() { | |
| // Calculate the convex hull as the outline of the intersection | |
| std::vector<Point> points; | |
| points.push_back(getPosition()); | |
| for (auto road : getRoads()){ | |
| Vector roadDirect = road->getEndIntersection().getPosition() - road->getStartIntersection().getPosition(); | |
| roadDirect = roadDirect.unit(); | |
| Vector pDirect = roadDirect.normal(); | |
| if (&road->getStartIntersection() == this) { | |
| roadDirect = -roadDirect; | |
| } | |
| /* <deltaWidth> | |
| * [pointB *]------[pointB1 *]-------- | |
| * | | |
| * v | |
| * [pDirect] <- roadDirect <- Road | |
| * | | |
| * v | |
| * [intersection]----[pointA *]------[pointA1 *]-------- | |
| */ | |
| double roadWidth = road->getWidth(); | |
| double deltaWidth = 0.5 * min2double(width, roadWidth); | |
| deltaWidth = max2double(deltaWidth, 5); | |
| Point pointA = getPosition() - roadDirect * width; | |
| Point pointB = pointA - pDirect * roadWidth; | |
| points.push_back(pointA); | |
| points.push_back(pointB); | |
| if (deltaWidth < road->averageLength()) { | |
| Point pointA1 = pointA - roadDirect * deltaWidth; | |
| Point pointB1 = pointB - roadDirect * deltaWidth; | |
| points.push_back(pointA1); | |
| points.push_back(pointB1); | |
| } | |
| } | |
| auto minIter = std::min_element(points.begin(), points.end(), | |
| [](const Point &a, const Point &b){ return a.y < b.y; }); | |
| Point p0 = *minIter; | |
| std::vector<Point> stack; | |
| stack.push_back(p0); | |
| points.erase(minIter); | |
| std::sort(points.begin(), points.end(), | |
| [&p0](const Point &a, const Point &b) | |
| {return (a - p0).ang() < (b - p0).ang(); }); | |
| for (size_t i = 0 ; i < points.size(); ++i) { | |
| Point &point = points[i]; | |
| Point p2 = stack[stack.size() - 1]; | |
| if (stack.size() < 2) { | |
| if (point.x != p2.x || point.y != p2.y) | |
| stack.emplace_back(point); | |
| continue; | |
| } | |
| Point p1 = stack[stack.size() - 2]; | |
| while (stack.size() > 1 && crossMultiply(point - p2, p2 - p1) >= 0) { | |
| p2 = p1; | |
| stack.pop_back(); | |
| if (stack.size() > 1) p1 = stack[stack.size() - 2]; | |
| } | |
| stack.emplace_back(point); | |
| } | |
| return stack; | |
| } | |
| bool Intersection::isImplicitIntersection() { | |
| return trafficLight.getPhases().size() <= 1; | |
| } | |
| void RoadLink::reset() { | |
| for (auto &laneLink : laneLinks) laneLink.reset(); | |
| } | |
| void LaneLink::reset() { | |
| vehicles.clear(); | |
| } | |
| void Lane::reset() { | |
| waitingBuffer.clear(); | |
| vehicles.clear(); | |
| } | |
| std::vector<Vehicle *> Lane::getVehiclesBeforeDistance(double dis, size_t segmentIndex, double deltaDis) { | |
| std::vector<Vehicle *> ret; | |
| for (int i = segmentIndex; i >=0 ;i--) { | |
| Segment * segment = getSegment(i); | |
| auto &vehicles = segment->getVehicles(); | |
| for(auto it = vehicles.begin(); it != vehicles.end(); ++it) { | |
| Vehicle *vehicle = *(*it); | |
| if (vehicle->getDistance() < dis - deltaDis) return ret; | |
| if (vehicle->getDistance() < dis) ret.emplace_back(vehicle); | |
| } | |
| } | |
| return ret; | |
| } | |
| void Lane::buildSegmentation(size_t numSegs) { | |
| this->segments.resize((unsigned) numSegs); | |
| for (size_t i = 0; i < numSegs; i++) { | |
| segments[i].index = i; | |
| segments[i].vehicles.clear(); | |
| segments[i].belongLane = this; | |
| segments[i].startPos = i * this->length / numSegs; | |
| segments[i].endPos = (i + 1) * this->length / numSegs; | |
| } | |
| } | |
| void Lane::initSegments() { | |
| auto iter = this->vehicles.begin(); | |
| auto end = this->vehicles.end(); | |
| for (int i = (int) segments.size() - 1; i >= 0; i--) { | |
| Segment &seg = segments[i]; | |
| seg.vehicles.clear(); | |
| while (iter != end && (*iter)->getDistance() >= seg.getStartPos()) { | |
| seg.vehicles.push_back(iter); | |
| (*iter)->setSegmentIndex(seg.index); | |
| ++iter; | |
| } | |
| } | |
| } | |
| Vehicle *Lane::getVehicleBeforeDistance(double dis, size_t segmentIndex) const{ | |
| for (int i = segmentIndex ; i >= 0 ; --i){ | |
| auto vehs = getSegment(i)->getVehicles(); | |
| for (auto itr = vehs.begin() ; itr != vehs.end(); ++itr){ | |
| auto &vehicle = **itr; | |
| if (vehicle->getDistance() < dis) return **itr; | |
| } | |
| } | |
| return nullptr; | |
| } | |
| Vehicle *Lane::getVehicleAfterDistance(double dis, size_t segmentIndex) const{ | |
| for (size_t i = segmentIndex ; i < getSegmentNum() ; ++i){ | |
| auto vehs = getSegment(i)->getVehicles(); | |
| for (auto itr = vehs.rbegin() ; itr != vehs.rend(); ++itr){ | |
| auto &vehicle = **itr; | |
| if (vehicle->getDistance() >= dis) return **itr; | |
| } | |
| } | |
| return nullptr; | |
| } | |
| void Lane::updateHistory() { | |
| double speedSum = historyVehicleNum * historyAverageSpeed; | |
| while (history.size() > historyLen){ | |
| historyVehicleNum -= history.front().vehicleNum; | |
| speedSum -= history.front().vehicleNum * history.front().averageSpeed; | |
| history.pop_front(); | |
| } | |
| double curSpeedSum = 0; | |
| int vehicleNum = getVehicles().size(); | |
| historyVehicleNum += vehicleNum; | |
| for (auto vehicle : getVehicles()) | |
| curSpeedSum += vehicle->getSpeed(); | |
| speedSum += curSpeedSum; | |
| history.emplace_back(vehicleNum, vehicleNum ? curSpeedSum / vehicleNum : 0); | |
| historyAverageSpeed = historyVehicleNum ? speedSum / historyVehicleNum : 0; | |
| } | |
| int Lane::getHistoryVehicleNum() const{ | |
| return historyVehicleNum; | |
| } | |
| double Lane::getHistoryAverageSpeed() const{ | |
| return historyAverageSpeed; | |
| } | |
| void Cross::reset() { } | |
| std::list<Vehicle *>::iterator Segment::findVehicle(Vehicle *vehicle) { | |
| for (auto itr = vehicles.begin() ; itr != vehicles.end() ; ++itr) | |
| if (**itr == vehicle) { | |
| return *itr; | |
| } | |
| return belongLane->getVehicles().end(); | |
| } | |
| void Segment::removeVehicle(Vehicle *vehicle) { | |
| for (auto itr = vehicles.begin() ; itr != vehicles.end() ; ++itr) | |
| if (**itr == vehicle) { | |
| vehicles.erase(itr); | |
| return; | |
| } | |
| } | |
| void Segment::insertVehicle(std::list<Vehicle *>::iterator &vehicle) { | |
| auto itr = vehicles.begin(); | |
| for (; itr != vehicles.end() && (**itr)->getDistance() > (*vehicle)->getDistance() ; ++itr); | |
| vehicles.insert(itr, vehicle); | |
| } | |
| } | |