rosaria/Legacy/Aria/ArNetworking/examples/drawingsExample.cpp
2021-12-16 14:07:59 +00:00

288 lines
8.4 KiB
C++

#include "Aria.h"
#include "ArNetworking.h"
#include <math.h>
/** @example drawingsExample.cpp Example showing how to draw custom graphics in
* clients such as MobileEyes
*
* This is an example server that shows how to draw arbitrary figures in a
* client (e.g. MobileEyes) via ArServerInfoDrawings. It draws some lines, "arrows", and moving dots
* with various sizes and colors. You can use these drawings for debugging
* or visualization, for example, to represent sensor readings. In fact,
* specific support for ArRobot, ArSick, ArSonarDevice, ArIRs and ArBumpers
* are built in to ArServerInfoDrawings: see drawingsExampleWithRobot.cpp
* or serverDemo.cpp.
*
* @sa drawingsExampleWithRobot.cpp
*/
/* These are some callbacks that respond to client requests for the drawings'
* geometry data. */
void exampleHomeDrawingNetCallback(ArServerClient* client, ArNetPacket* requestPkt);
void exampleDotsDrawingNetCallback(ArServerClient* client, ArNetPacket* requestPkt);
void exampleXDrawingNetCallback(ArServerClient* client, ArNetPacket* requestPkt);
void exampleArrowsDrawingNetCallback(ArServerClient* client, ArNetPacket* requestPkt);
/* This class shows how to encapsulate the various aspects of a drawing into one
* object that other parts of the program can easily access in a more general
* (and thread-safe) way. It lets you change position, radius, resolution
* (number of dots), and dot drawing properties.
* The default radius is 1 meter and the default number of points is 360.
*
* In this example program, the radius is updated periodically by a loop in the
* main thread (see main() function), while ArNetworking requests are handled
* in the separate ArNetworking server thread, calling drawingServerCB() callback (this is
* registered with the server when we register the drawing with the
* ArServerInfoDrawings object). So note the use of an ArMutex object to
* control this asyrchronous access to the reply packet.
*/
class Circle
{
private:
ArNetPacket myReply;
ArMutex myMutex; // mutex around myReply
ArPose myPos;
double myRadius;
unsigned int myNumPoints;
void drawingServerCB(ArServerClient *client, ArNetPacket *pkt);
ArFunctor2C<Circle, ArServerClient*, ArNetPacket*> callback;
void regenerate();
public:
Circle(ArServerInfoDrawings *drawingsServer, const std::string& name, ArDrawingData *drawData);
~Circle();
void setPos(const ArPose& p)
{
myPos = p;
regenerate();
}
void setRadius(double r)
{
myRadius = r;
regenerate();
}
void setNumPoints(unsigned int r)
{
myNumPoints = r;
regenerate();
}
};
Circle::Circle(ArServerInfoDrawings *drawingsServer, const std::string& name, ArDrawingData* drawData) :
myRadius(1000.0),
myNumPoints(360),
callback(this, &Circle::drawingServerCB)
{
drawingsServer->addDrawing(drawData, name.c_str(), &callback);
}
Circle::~Circle()
{
// TODO remove drawing from the server, but not implemented yet
}
void Circle::drawingServerCB(ArServerClient *client, ArNetPacket *pkt)
{
myMutex.lock();
client->sendPacketUdp(&myReply);
myMutex.unlock();
}
// Method called by accessor methods when properties changed. This reconstructs
// the myReply packet sent in response to requests from clients
void Circle::regenerate()
{
myMutex.lock();
myReply.empty();
myReply.byte4ToBuf(myNumPoints);
double a = 360.0/myNumPoints;
for(unsigned int i = 0; i < myNumPoints; ++i)
{
myReply.byte4ToBuf(ArMath::roundInt(myPos.getX()+ArMath::cos(i*a)*myRadius)); // X
myReply.byte4ToBuf(ArMath::roundInt(myPos.getY()+ArMath::sin(i*a)*myRadius)); // Y
}
myMutex.unlock();
}
int main(int argc, char **argv)
{
Aria::init();
ArServerBase server;
ArArgumentParser parser(&argc, argv);
ArServerSimpleOpener simpleOpener(&parser);
// parse the command line... fail and print the help if the parsing fails
// or if help was requested
parser.loadDefaultArguments();
if (!simpleOpener.parseArgs() || !parser.checkHelpAndWarnUnparsed())
{
simpleOpener.logOptions();
exit(1);
}
// first open the server up
if (!simpleOpener.open(&server))
{
if (simpleOpener.wasUserFileBad())
printf("Error: Bad user/password/permissions file.\n");
else
printf("Error: Could not open server port. Use -help to see options.\n");
exit(1);
}
// This is the service that provides drawing data to the client.
ArServerInfoDrawings drawings(&server);
// Add our custom drawings
drawings.addDrawing(
// shape: color: size: layer:
new ArDrawingData("polyLine", ArColor(255, 0, 0), 2, 49),
"exampleDrawing_Home",
new ArGlobalFunctor2<ArServerClient*, ArNetPacket*>(&exampleHomeDrawingNetCallback)
);
drawings.addDrawing(
new ArDrawingData("polyDots", ArColor(0, 255, 0), 250, 48),
"exampleDrawing_Dots",
new ArGlobalFunctor2<ArServerClient*, ArNetPacket*>(&exampleDotsDrawingNetCallback)
);
drawings.addDrawing(
new ArDrawingData("polySegments", ArColor(0, 0, 0), 4, 52),
"exampleDrawing_XMarksTheSpot",
new ArGlobalFunctor2<ArServerClient*, ArNetPacket*>(&exampleXDrawingNetCallback)
);
drawings.addDrawing(
new ArDrawingData("polyArrows", ArColor(255, 0, 255), 500, 100),
"exampleDrawing_Arrows",
new ArGlobalFunctor2<ArServerClient*, ArNetPacket*>(&exampleArrowsDrawingNetCallback)
);
Circle circle(&drawings, "exampleDrawing_circle",
new ArDrawingData("polySegments", ArColor(255, 150, 0), 3, 120));
circle.setPos(ArPose(0, -5000));
circle.setRadius(1000);
circle.setNumPoints(360);
// log whatever we wanted to before the runAsync
simpleOpener.checkAndLog();
// run the server thread in the background
server.runAsync();
printf("Server is now running...\n");
// Add a key handler mostly that windows can exit by pressing
// escape, note that the key handler prevents you from running this program
// in the background on Linux.
ArKeyHandler *keyHandler;
if ((keyHandler = Aria::getKeyHandler()) == NULL)
{
keyHandler = new ArKeyHandler;
Aria::setKeyHandler(keyHandler);
printf("To exit, press escape.\n");
}
double circleRadius = 1000;
while(true)
{
ArUtil::sleep(100);
circleRadius += 50;
if(circleRadius > 5000)
circleRadius = 0;
circle.setRadius(circleRadius);
}
Aria::shutdown();
exit(0);
}
// Network callbacks for drawings' current geometry data:
void exampleHomeDrawingNetCallback(ArServerClient* client, ArNetPacket* requestPkt) {
ArNetPacket reply;
// 7 Vertices
reply.byte4ToBuf(7);
// Centered on 0,0.
// X: Y:
reply.byte4ToBuf(-500); reply.byte4ToBuf(500); // Vertex 1
reply.byte4ToBuf(-500); reply.byte4ToBuf(-500); // Vertex 2
reply.byte4ToBuf(500); reply.byte4ToBuf(-500); // Vertex 3
reply.byte4ToBuf(500); reply.byte4ToBuf(500); // Vertex 4
reply.byte4ToBuf(0); reply.byte4ToBuf(1000); // Vertex 5
reply.byte4ToBuf(-500); reply.byte4ToBuf(500); // Vertex 6
reply.byte4ToBuf(500); reply.byte4ToBuf(500); // Vertex 7
client->sendPacketUdp(&reply);
}
void exampleDotsDrawingNetCallback(ArServerClient* client, ArNetPacket* requestPkt) {
ArNetPacket reply;
unsigned int tik = ArUtil::getTime() % 200;
double t = tik / 5.0;
// Three dots
reply.byte4ToBuf(3);
// Dot 1:
reply.byte4ToBuf(3000); // X coordinate (mm)
reply.byte4ToBuf((int) (sin(t) * 1000));// Y
// Dot 2:
reply.byte4ToBuf(3500); // X
reply.byte4ToBuf((int) (sin(t+500) * 1000));// Y
// Dot 3:
reply.byte4ToBuf(4000); // X
reply.byte4ToBuf((int) (sin(t+1000) * 1000));// Y
client->sendPacketUdp(&reply);
}
void exampleXDrawingNetCallback(ArServerClient* client, ArNetPacket* requestPkt) {
ArNetPacket reply;
// X marks the spot. 2 line segments, so 4 vertices:
reply.byte4ToBuf(4);
// Segment 1:
reply.byte4ToBuf(-4250); // X1
reply.byte4ToBuf(250); // Y1
reply.byte4ToBuf(-3750); // X2
reply.byte4ToBuf(-250); // Y2
// Segment 2:
reply.byte4ToBuf(-4250); // X1
reply.byte4ToBuf(-250); // Y1
reply.byte4ToBuf(-3750); // X2
reply.byte4ToBuf(250); // Y2
client->sendPacketUdp(&reply);
}
void exampleArrowsDrawingNetCallback(ArServerClient* client, ArNetPacket* requestPkt) {
// 1 Arrow that points at the robot
ArNetPacket reply;
reply.byte4ToBuf(1);
reply.byte4ToBuf(0); // Pos. X
reply.byte4ToBuf(700); // Pos. Y
client->sendPacketUdp(&reply);
}