Commit 72b44877 authored by pitiot's avatar pitiot

Merge fini

parent d8445613
......@@ -43,6 +43,7 @@ add_executable( socialAgentsD
../src/gl2ps.c
../src/ShapeMatching/rigidXfComputation.cpp
../src/shaderCustom.cpp
../src/shaderCustomTex.cpp
${socialAgents_moc}
${socialAgents_ui}
)
......
......@@ -43,6 +43,7 @@ add_executable( socialAgents
../src/gl2ps.c
../src/ShapeMatching/rigidXfComputation.cpp
../src/shaderCustom.cpp
../src/shaderCustomTex.cpp
${socialAgents_moc}
${socialAgents_ui}
)
......
......@@ -7,7 +7,10 @@
#include "env_map.h"
#include "spatialHashing.h"
//#define SECURED
#define EXPORTING_AGENT
//#define EXPORTING_OBJ
#ifdef SECURED
#include "Algo/MovingObjects/particle_cell_2D_secured.h"
......@@ -15,6 +18,19 @@
#include "Algo/MovingObjects/particle_cell_2D.h"
#endif
#ifdef EXPORTING_AGENT
#include "Utils/vbo.h"
#include "Utils/Shaders/shaderSimpleColor.h"
#endif
#ifdef EXPORTING_OBJ
#include "Algo/Render/GL2/mapRender.h"
#include "Utils/vbo.h"
#include "Algo/Import/importObjTex.h"
#include "shaderCustomTex.h"
#endif
class Simulator ;
class Agent
......@@ -24,6 +40,8 @@ public:
Agent(Simulator* sim, const VEC3& position, const VEC3& goals) ;
void init(const VEC3& start, const VEC3& goal);
void initGL();
void draw();
VEC3 getPosition() ;
......@@ -50,6 +68,32 @@ public:
std::vector<std::pair<float, Obstacle*> > obstacleNeighbors_ ;
std::vector<std::pair<float, Obstacle*> > movingObstacleNeighbors_;
#ifdef EXPORTING_AGENT
static const int m_ghost_nb = 500;
std::list<VEC3> m_ghost_previousPos;
Utils::VBO * m_ghost_VBO;
Utils::ShaderSimpleColor * m_ghost_shader;
#endif
#ifdef EXPORTING_OBJ
PFP2::MAP map;
VertexAttribute<VEC3> position;
VertexAttribute<VEC3> normal;
VEC3 previousPos;
float previousRot;
Algo::Render::GL2::MapRender* m_render;
Utils::VBO* m_positionVBO;
Utils::VBO* m_normalVBO;
Utils::Texture<2,Geom::Vec3uc>* m_texture;
Utils::VBO* m_texcoordVBO;
ShaderCustomTex* m_shaderTex;
Algo::Surface::Import::OBJModel<PFP2> m_obj;
unsigned int m_nbIndices;
#endif
#ifdef SPATIAL_HASHING
VEC3 pos ;
#else
......
......@@ -606,15 +606,16 @@ void generatePlanet(EnvMap& envMap)
{
unsigned int nx = envMap.geometry.size(0) / envMap.maxCellSize ;
unsigned int ny = envMap.geometry.size(1) / envMap.maxCellSize ;
if (nx < 1) nx = 1 ;
if (ny < 1) ny = 1 ;
if (nx < 1)
nx = 1 ;
if (ny < 1)
ny = 1 ;
Algo::Surface::Modelisation::Polyhedron<PFP> prim(envMap.map, envMap.position) ;
prim.cylinder_topo(nx, ny, true, true) ;
double pi = 3.14159265358979323846f ;
double xRadius = envMap.geometry.size(0) / 2 * pi ;
double yRadius = envMap.geometry.size(1) / 2 * pi ;
double xRadius = envMap.geometry.size(0) / 2 * M_PI;
double yRadius = envMap.geometry.size(1) / 2 * M_PI ;
prim.embedSphere((xRadius+yRadius)/2.0f) ;
}
......@@ -624,6 +625,7 @@ typename PFP::VEC3 parametrization(typename PFP::VEC3 p, float r,const Geom::Bou
{
p[0] = 2.0f*M_PI*(p[0]-bb.min()[0])/bb.size(0);
p[1] = ((2.0f*M_PI*(p[1]-bb.min()[1])/bb.size(1))-M_PI)/2.0f;
r += p[2];
return typename PFP::VEC3(2.0f*r*cos(p[0])*cos(p[1]),
2.0f*r*sin(p[0])*cos(p[1]),
......
......@@ -32,6 +32,15 @@ class ArticulatedObstacle;
#include "pfp.h"
#define EXPORTING3
#ifdef EXPORTING3
#include "Utils/Shaders/shaderPhongTexture.h"
#include "Utils/Shaders/shaderSimpleTexture.h"
#include "shaderCustomTex.h"
#include "Algo/Import/importObjTex.h"
#endif
class EnvMap
{
public:
......@@ -52,6 +61,9 @@ public:
EnvMap() ;
void init(unsigned int config, REAL width, REAL height, REAL minSize, REAL maxSize) ;
void initGL();
void draw();
void scale(float val);
void markPedWay() ;
......@@ -96,6 +108,8 @@ public:
PFP::TVEC3 position ;
PFP::TVEC3 normal ;
Geom::BoundingBox<PFP::VEC3> bb;
PFP::MAP mapScenary ;
PFP::TVEC3 positionScenary ;
PFP::TVEC3 normalScenary ;
......@@ -112,6 +126,32 @@ public:
void popObstNeighborInCells(Obstacle* o, Dart d);
void find_next(Obstacle* o,Dart * d, CellMarkerMemo<FACE>& cms);
#ifdef EXPORTING3
std::vector<PFP::MAP *> m_map_Export;
std::vector<Algo::Surface::Import::OBJModel<PFP2> *> m_obj_Export;
std::vector<Utils::Texture<2,Geom::Vec3uc>*> m_texture_Export;
std::vector<Utils::VBO*> m_positionVBO_Export;
std::vector<Utils::VBO*> m_normalVBO_Export;
std::vector<Utils::VBO*> m_texcoordVBO_Export;
std::vector<ShaderCustomTex*> m_shaderTex_Export;
std::vector<unsigned int> m_nbIndice_Export;
// PFP2::MAP m_map_Export;
// VertexAttribute<VEC3> position_Export ;
// VertexAttribute<VEC3> normal_Export ;
// Algo::Surface::Import::OBJModel<PFP2> * m_obj_Export;
//
// Utils::Texture<2,Geom::Vec3uc>* m_texture_Export;
// Utils::VBO* m_positionVBO_Export;
// Utils::VBO* m_normalVBO_Export;
// Utils::VBO* m_texcoordVBO_Export;
// ShaderCustomTex* m_shaderTex_Export;
//
// unsigned int m_nbIndice_Export;
#endif
std::vector<Dart> newBuildings ;
......@@ -247,15 +287,15 @@ inline void EnvMap::pushAgentInCells(Agent* agent, Dart d)
// assert(std::find(agentvect[d].begin(), agentvect[d].end(), agent) == agentvect[d].end());
// map.check();
TraversorF<PFP::MAP> tF(map);
for(Dart ddd = tF.begin() ; ddd != tF.end() ; ddd = tF.next())
{
if(std::find(agentvect[ddd].begin(), agentvect[ddd].end(), agent) != agentvect[ddd].end())
std::cout <<agent << " SO WRONG ADD" <<ddd.index<< std::endl;
if(std::find(neighborAgentvect[ddd].begin(), neighborAgentvect[ddd].end(), agent) != neighborAgentvect[ddd].end())
std::cout <<agent<< " SO SO WRONG ADD" <<ddd.index<< std::endl;
}
// TraversorF<PFP::MAP> tF(map);
// for(Dart ddd = tF.begin() ; ddd != tF.end() ; ddd = tF.next())
// {
// if(std::find(agentvect[ddd].begin(), agentvect[ddd].end(), agent) != agentvect[ddd].end())
// std::cout <<agent << " SO WRONG ADD" <<ddd.index<< std::endl;
//
// if(std::find(neighborAgentvect[ddd].begin(), neighborAgentvect[ddd].end(), agent) != neighborAgentvect[ddd].end())
// std::cout <<agent<< " SO SO WRONG ADD" <<ddd.index<< std::endl;
// }
addElementToVector<Agent*>(agentvect[d],agent);
// agentvect[d].push_back(agent) ;
......@@ -267,7 +307,11 @@ inline void EnvMap::pushAgentInCells(Agent* agent, Dart d)
Dart ddd = map.alpha1(map.alpha1(dd)) ;
while (ddd != dd)
{
addElementToVector<Agent*>(neighborAgentvect[ddd],agent);
if (!map.isBoundaryMarked2(ddd))
{
addElementToVector<Agent*>(neighborAgentvect[ddd],agent);
}
// neighborAgentvect[ddd].push_back(agent) ;
// nbAgentsIncrease(ddd);
ddd = map.alpha1(ddd) ;
......@@ -289,22 +333,25 @@ inline void EnvMap::popAgentInCells(Agent* agent, Dart d)
Dart ddd = map.alpha1(map.alpha1(dd)) ;
while (ddd != dd)
{
removeElementFromVector<Agent*>(neighborAgentvect[ddd], agent) ;
if (!map.isBoundaryMarked2(ddd))
{
removeElementFromVector<Agent*>(neighborAgentvect[ddd], agent) ;
}
// nbAgentsDecrease(ddd) ;
ddd = map.alpha1(ddd) ;
}
dd = map.phi1(dd) ;
} while (dd != d) ;
TraversorF<PFP::MAP> tF(map);
for(Dart ddd = tF.begin() ; ddd != tF.end() ; ddd = tF.next())
{
if(std::find(agentvect[ddd].begin(), agentvect[ddd].end(), agent) != agentvect[ddd].end())
std::cout <<agent << " SO WRONG" <<ddd.index<< std::endl;
if(std::find(neighborAgentvect[ddd].begin(), neighborAgentvect[ddd].end(), agent) != neighborAgentvect[ddd].end())
std::cout <<agent<< " SO SO WRONG " <<ddd.index<< std::endl;
}
// TraversorF<PFP::MAP> tF(map);
// for(Dart ddd = tF.begin() ; ddd != tF.end() ; ddd = tF.next())
// {
// if(std::find(agentvect[ddd].begin(), agentvect[ddd].end(), agent) != agentvect[ddd].end())
// std::cout <<agent << " SO WRONG" <<ddd.index<< std::endl;
//
// if(std::find(neighborAgentvect[ddd].begin(), neighborAgentvect[ddd].end(), agent) != neighborAgentvect[ddd].end())
// std::cout <<agent<< " SO SO WRONG " <<ddd.index<< std::endl;
// }
}
......
......@@ -13,15 +13,20 @@
#include "Utils/Shaders/shaderSimpleColor.h"
#include "Utils/Qt/qtSimple.h"
using namespace std;
#include "Utils/Shaders/shaderSimpleTexture.h"
#include "Algo/Import/importObjTex.h"
using namespace std;
//#define EXPORTING2
class MovingMesh
{
public:
MovingMesh(EnvMap& envMap, Dart d, std::string filename);
void initGL();
void linkWithObstacle(MovingObstacle * mo);
void transform(Geom::Matrix44f m);
......@@ -40,14 +45,26 @@ public:
PFP::MAP& motherMap;
VertexAttribute<VEC3>& motherPosition;
PFP::MAP map;
PFP2::MAP map;
VertexAttribute<VEC3> position;
VertexAttribute<VEC3> normal;
Algo::Render::GL2::MapRender* m_render;
Utils::VBO* m_positionVBO;
Utils::VBO* m_normalVBO;
#ifdef EXPORTING2
Utils::Texture<2,Geom::Vec3uc>* m_texture;
Utils::VBO* m_texcoordVBO;
ShaderCustomTex* m_shaderTex;
// Utils::ShaderPhongTexture* m_shaderTex;
// Utils::ShaderSimpleTexture* m_shaderTex;
Algo::Surface::Import::OBJModel<PFP2> m_obj;
unsigned int m_nbIndices;
#else
Utils::ShaderSimpleColor* m_simpleColorShader;
#endif
float scaleValue;
......
......@@ -8,6 +8,15 @@
#include <set>
#include "Algo/MovingObjects/particle_cell_2D_memo.h"
//#define EXPORTING_BOXES
#ifdef EXPORTING_BOXES
#include "Algo/Render/GL2/mapRender.h"
#include "Utils/Shaders/shaderSimpleColor.h"
#include "Utils/Shaders/shaderFlat.h"
#include "Utils/vbo.h"
#endif
using namespace std;
PFP::VEC3 rotate (PFP::VEC3 pos1, PFP::VEC3 center, float angle);
float get_angle (PFP::VEC3 v1, PFP::VEC3 v2);
......@@ -19,6 +28,9 @@ class MovingObstacle
{
public:
MovingObstacle(Simulator* sim, int index, std::vector<PFP::VEC3> pos, std::vector<VEC3> goals, bool rigid, bool spin,int curGoal=0, Dart d=NIL, ArticulatedObstacle * art=NULL, int indParent=-1);
void initGL();
void draw();
bool test_opposition(VEC3 o, VEC3 p1, VEC3 p2);
// void contournerBatiment();
void updateAgentNeighbors() ;
......@@ -53,6 +65,13 @@ public:
Dart groundFace;
#ifdef EXPORTING_BOXES
Algo::Render::GL2::MapRender* m_render;
Utils::VBO* m_positionVBO;
Utils::VBO* m_normalVBO;
Utils::ShaderSimpleColor* m_shader;
#endif
//vector de détails pour la deformation
// std::vector<PFP::VEC3> verticesDeformation;
......
......@@ -24,6 +24,13 @@ struct PFP : public PFP_STANDARD
typedef NoMathIONameAttribute<std::pair<bool, bool> > BOOLATTRIB ;
} ;
struct PFP2 : public PFP_STANDARD
{
// definition de la carte
// typedef EmbeddedMap2 MAP ;
typedef Algo::Surface::IHM::ImplicitHierarchicalMap MAP ;
} ;
typedef PFP::VEC3 VEC3 ;
typedef PFP::REAL REAL ;
......
......@@ -94,7 +94,7 @@ public:
void setupCorridorScenario(unsigned int nbAgents, unsigned int nbObstacles) ;
void setupSnakeCorridorScenario(unsigned int nbAgents, unsigned int nbSnakes, int snakeSize) ;
void setupCityScenario(int nbLines, int nbRank) ;
void setupScenario(unsigned int nbMaxAgent, bool path) ;
void setupScenario(unsigned int nbMaxAgent, bool pedWay=false) ;
void addMovingObstacles(unsigned int nb);
void addMovingObstacle(Dart d, unsigned int obstType=0);
......@@ -112,7 +112,6 @@ public:
bool importAgents(std::string filename) ;
bool exportAgents(std::string filename) ;
void checkRegistering();
void swapAgentsGoals() ;
Geom::BoundingBox<VEC3> getAgentsBB() ;
......
......@@ -83,8 +83,7 @@ public:
void exportInfoFace(std::ofstream& out, Dart d) ;
bool exportScenePov(PFP::MAP& map, PFP::TVEC3& position, const std::string& filename,
PFP::VEC3 cameraPos, PFP::VEC3 cameraLook, PFP::VEC3 translate,
float angle_X, float angle_Y, float angle_Z,
const FunctorSelect& good = SelectorTrue()) ;
float angle_X, float angle_Y, float angle_Z) ;
#endif
void cb_keyPress(int keycode) ;
......
......@@ -27,6 +27,9 @@ float Agent::rangeSq_ = range_ * range_ ;
unsigned int Agent::cptAgent = 0 ;
Agent::Agent(Simulator* sim, const VEC3& start, const VEC3& goal, Dart d) :
#ifdef EXPORTING_OBJ
m_obj(map),
#endif
#ifdef SPATIAL_HASHING
pos(position),
#else
......@@ -44,6 +47,9 @@ Agent::Agent(Simulator* sim, const VEC3& start, const VEC3& goal, Dart d) :
}
Agent::Agent(Simulator* sim, const VEC3& start, const VEC3& goal) :
#ifdef EXPORTING_OBJ
m_obj(map),
#endif
#ifdef SPATIAL_HASHING
pos(position),
#else
......@@ -62,6 +68,12 @@ Agent::Agent(Simulator* sim, const VEC3& start, const VEC3& goal) :
void Agent::init(const VEC3& start, const VEC3& goal)
{
#ifdef EXPORTING_OBJ
std::vector<std::string> attrNames ;
m_obj.import("./meshRessources/Mexicainlowres.obj",attrNames);
position = map.getAttribute<VEC3, VERTEX>(attrNames[0]) ;
#endif
#ifdef SPATIAL_HASHING
sim->envMap_.addAgentInGrid(this) ;
#endif
......@@ -88,9 +100,97 @@ void Agent::init(const VEC3& start, const VEC3& goal)
movingObstacles_ = new MovingObstacle* [maxMovingObstacles_];
nb_mos=0;
agentNo = cptAgent++ ;
CGoGNout<<this<<" = agent n°"<<agentNo<<CGoGNendl;
// CGoGNout<<this<<" = agent n°"<<agentNo<<CGoGNendl;
}
void Agent::initGL()
{
#ifdef EXPORTING_AGENT
m_ghost_shader = new Utils::ShaderSimpleColor();
m_ghost_shader->setColor(Geom::Vec4f(1.,0.,0.,0.));
// m_ghost_shader->setAmbiant(Geom::Vec4f(1.,1.,0.,0.)) ;
// m_ghost_shader->setDiffuse(Geom::Vec4f(1.,1.,0.,0.));
m_ghost_VBO = new Utils::VBO();
m_ghost_VBO->setDataSize(3);
m_ghost_VBO->allocate(m_ghost_nb);
m_ghost_shader->setAttributePosition(m_ghost_VBO);
// registerShader(m_ghost_shader);
#endif
#ifdef EXPORTING_OBJ
m_texcoordVBO = new Utils::VBO();
m_positionVBO = new Utils::VBO();
m_normalVBO = new Utils::VBO();
m_texture = new Utils::Texture<2,Geom::Vec3uc>(GL_UNSIGNED_BYTE);
if (m_texture->load("./meshRessources/sombrero2lowres_grp.png"))
m_texture->update();
else
std::cout << "problem : loading texture" << std::endl;
m_texture->setWrapping(GL_CLAMP_TO_EDGE);
m_shaderTex = new ShaderCustomTex();
m_shaderTex->setAttributePosition(m_positionVBO);
m_shaderTex->setAttributeTexCoord(m_texcoordVBO);
m_shaderTex->setTextureUnit(GL_TEXTURE0);
m_shaderTex->setTexture(m_texture);
glEnable(GL_TEXTURE_2D);
if (!m_obj.hasNormals())
{
normal = map.getAttribute<VEC3, VERTEX>("normal") ;
if(!normal.isValid())
normal = map.addAttribute<VEC3, VERTEX>("normal") ;
Algo::Surface::Geometry::computeNormalVertices<PFP2>(map, m_obj.m_positions, normal) ;
m_obj.setNormalAttribute(normal);
}
map.setBrowser(NULL);
m_nbIndices = m_obj.createSimpleVBO_PTN(m_positionVBO,m_texcoordVBO,m_normalVBO);
previousPos = VEC3(0,0,0);
#endif
}
void Agent::draw()
{
#ifdef EXPORTING_AGENT
PFP::VEC3* data = static_cast<PFP::VEC3*>(m_ghost_VBO->lockPtr());
unsigned int i = 0;
for(std::list<VEC3>::iterator it = m_ghost_previousPos.begin() ; it != m_ghost_previousPos.end() ; ++it, ++i)
{
data[i] = *it;
}
m_ghost_VBO->releasePtr();
m_ghost_shader->enableVertexAttribs();
glDrawArrays(GL_LINE_STRIP, 0, m_ghost_previousPos.size());
m_ghost_shader->disableVertexAttribs();
#endif
#ifdef EXPORTING_OBJ
Algo::Surface::Geometry::computeNormalVertices<PFP2>(map, m_obj.m_positions, normal) ;
m_nbIndices = m_obj.createSimpleVBO_PTN(m_positionVBO,m_texcoordVBO,m_normalVBO);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
m_shaderTex->activeTexture();
m_shaderTex->enableVertexAttribs();
glDrawArrays(GL_TRIANGLES, 0, m_nbIndices);
m_shaderTex->disableVertexAttribs();
#endif
}
//-----------------------------------------------------------------
//-----------------------------------------------------------------
......@@ -217,7 +317,7 @@ void Agent::updateObstacleNeighbors()
if ((obstacleNeighbors_.size() < maxMovingObstacles_|| distSq < maxDistObst)
&& distSq < rangeSq_)
{
// if (Geom::testOrientation2D(part_.getPosition(), (*it)->p1, (*it)->p2) == Geom::RIGHT)
if (Geom::testOrientation2D(part_.getPosition(), (*it)->p1, (*it)->p2) == Geom::RIGHT)
{
if (distSq > maxDistObst)
......@@ -236,7 +336,7 @@ void Agent::updateObstacleNeighbors()
if ((movingObstacleNeighbors_.size() < maxMovingObstacles_ || distSq < maxDistMovingObst)
&& distSq < rangeSq_)
{
// if (Geom::testOrientation2D(part_.getPosition(), (*it)->p1, (*it)->p2) == Geom::RIGHT)
if (Geom::testOrientation2D(part_.getPosition(), (*it)->p1, (*it)->p2) == Geom::RIGHT)
{
if (distSq > maxDistMovingObst)
......@@ -253,37 +353,37 @@ void Agent::updateObstacleNeighbors()
for(std::vector<Obstacle*>::const_iterator it = neighborObst.begin() ; it != neighborObst.end() ; ++it)
{
if ((*it)->mo==NULL)
{
float distSq = distSqPointLineSegment((*it)->p1, (*it)->p2, part_.getPosition()) ;
if ((obstacleNeighbors_.size() < maxNeighbors_ || distSq < maxDistObst)
&&distSq < rangeSq_)
{
if (Geom::testOrientation2D(part_.getPosition(), (*it)->p1, (*it)->p2) == Geom::RIGHT)
{
float distSq = distSqPointLineSegment((*it)->p1, (*it)->p2, part_.getPosition()) ;
if ((obstacleNeighbors_.size() < maxNeighbors_ || distSq < maxDistObst)
&&distSq < rangeSq_)
{
// if (Geom::testOrientation2D(part_.getPosition(), (*it)->p1, (*it)->p2) == Geom::RIGHT)
{
if (distSq > maxDistObst) maxDistObst = distSq ;
obstacleNeighbors_.push_back(std::make_pair(distSq, *it)) ;
}
if (distSq > maxDistObst) maxDistObst = distSq ;
obstacleNeighbors_.push_back(std::make_pair(distSq, *it)) ;
}
}
else
{
float distSq = distSqPointLineSegment((*it)->p1, (*it)->p2, part_.getPosition()) ;
if ((movingObstacleNeighbors_.size() < maxNeighbors_ || distSq < maxDistMovingObst)
&&distSq < rangeSq_)
{
// if (Geom::testOrientation2D(part_.getPosition(), (*it)->p1, (*it)->p2) == Geom::RIGHT)
{
if (distSq > maxDistMovingObst) maxDistMovingObst = distSq ;
movingObstacleNeighbors_.push_back(std::make_pair(distSq, *it)) ;
}
}
else
{
float distSq = distSqPointLineSegment((*it)->p1, (*it)->p2, part_.getPosition()) ;
if ((movingObstacleNeighbors_.size() < maxNeighbors_ || distSq < maxDistMovingObst)
&&distSq < rangeSq_)
{
if (Geom::testOrientation2D(part_.getPosition(), (*it)->p1, (*it)->p2) == Geom::RIGHT)
{
}
if (distSq > maxDistMovingObst) maxDistMovingObst = distSq ;
movingObstacleNeighbors_.push_back(std::make_pair(distSq, *it)) ;
}
}
}
}
}
if (obstacleNeighbors_.size() > maxNeighbors_)
{
......@@ -321,7 +421,6 @@ void Agent::updateObstacleNeighbors()
// }
}
//-----------------------------------------------------------------
//-----------------------------------------------------------------
......@@ -339,7 +438,13 @@ void Agent::update()
#ifdef SECURED
if(target != part_.getPosition())
std::cout << "Problem agent " << agentNo << " (position : " << part_.getPosition() << ") time " << sim_->globalTime_ << std::endl;
std::cout << "Problem agent " << agentNo << " (position : " << part_.getPosition() << ") time " << sim_->nbSteps_ << std::endl;
#endif
#ifdef EXPORTING_AGENT
m_ghost_previousPos.push_back(target);
if(m_ghost_previousPos.size()>m_ghost_nb)
m_ghost_previousPos.pop_front();
#endif
#endif
......@@ -351,6 +456,27 @@ void Agent::update()
meanVelocity_[3] = velocity_ ;