dust3d/thirdparty/cgal/CGAL-4.13/include/CGAL/IO/Geomview_stream_impl.h

614 lines
15 KiB
C++
Executable File

// Copyright (c) 1999-2004
// Utrecht University (The Netherlands),
// ETH Zurich (Switzerland),
// INRIA Sophia-Antipolis (France),
// Max-Planck-Institute Saarbruecken (Germany),
// and Tel-Aviv University (Israel). All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 3 of the License,
// or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0+
//
//
// Author(s) : Andreas Fabri, Herve Bronnimann, Sylvain Pion
#ifdef CGAL_USE_GEOMVIEW
#ifdef CGAL_HEADER_ONLY
#define CGAL_INLINE_FUNCTION inline
#else
#define CGAL_INLINE_FUNCTION
#endif
#include <sstream>
#include <csignal>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h> // kill() on SunPro requires these 2 #includes.
#include <signal.h>
#include <CGAL/IO/binary_file_io.h>
namespace CGAL {
CGAL_INLINE_FUNCTION
Geomview_stream::Geomview_stream(const Bbox_3 &bbox,
const char *machine,
const char *login)
: bb(bbox), vertex_color(BLACK), edge_color(BLACK), face_color(BLACK),
wired_flag(false), echo_flag(true), raw_flag(false),
trace_flag(false), binary_flag(false),
line_width(1)
{
setup_geomview(machine, login);
frame(bbox);
pickplane(bbox);
set_vertex_radius((bbox.xmax() - bbox.xmin())/100.0);
}
CGAL_INLINE_FUNCTION
Geomview_stream::~Geomview_stream()
{
kill(pid, SIGKILL); // kills geomview
}
CGAL_INLINE_FUNCTION
void Geomview_stream::setup_geomview(const char *machine, const char *login)
{
int pipe_out[2], pipe_in[2];
// Communication between CGAL and geomview should be possible
// in two directions. To achieve this we open two pipes
std::cout << "Starting Geomview..." << std::flush;
if (pipe(pipe_out) < 0) {
CGAL_error_msg( "out pipe failed" );
}
if (pipe(pipe_in) < 0) {
CGAL_error_msg( "in pipe failed" );
}
switch (pid = fork()){
case -1:
CGAL_error_msg( "fork failed" );
case 0: // The child process
close(pipe_out[1]); // does not write to the out pipe,
close(pipe_in[0]); // does not read from the in pipe.
if (dup2(pipe_out[0], 0) != 0)
std::cerr << "Connect pipe to stdin failed." << std::endl;
if (dup2(pipe_in[1], 1) != 1)
std::cerr << "Connect pipe to stdout failed." << std::endl;
if (machine && (std::strlen(machine)>0)) {
std::string s (" rgeomview ");
s += machine;
s += ":0.0";
execlp("rsh", "rsh", machine, "-l", login, s.data(),
static_cast<void *>(NULL)); // cast to stop gcc warning
} else {
execlp("geomview", "geomview", "-c", "-",
static_cast<void *>(NULL)); // cast to stop gcc warning
}
// if we get to this point something went wrong.
std::cerr << "execl geomview failed" << std::endl;
switch(errno) {
case EACCES:
std::cerr << "please check your environment variable PATH"
<< std::endl;
std::cerr << "make sure the file `geomview' is contained in it"
<< std::endl;
std::cerr << "and is executable" << std::endl;
break;
case ELOOP:
std::cerr << "too many links for filename `geomview'" << std::endl;
break;
default:
std::cerr << "error number " << errno << " (check `man execlp')"
<< std::endl;
};
CGAL_error();
default: // The parent process
close(pipe_out[0]); // does not read from the out pipe,
close(pipe_in[1]); // does not write to the in pipe.
in = pipe_in[0];
out = pipe_out[1];
// Necessary to wait a little bit for Geomview,
// otherwise you won't be able to ask for points...
sleep(1);
#if 1
// We want to get rid of the requirement in the CGAL doc about
// (echo "started"). But we want to be backward compatible, that is,
// people who have this echo in their .geomview must still have CGAL
// working, at least for a few public releases.
// So the plan is to send, from CGAL, the command : (echo "CGAL-3D")
// It's the same length as "started", 7.
// Then we read 7 chars from Geomview, and test which string it is.
// If it's "CGAL-3D", then fine, the user doesn't have .geomview with
// the back-compatible echo command.
// In the very long run, we'll be able to get rid of all this code as
// well.
// Maybe we should simply read the pipe, till we find "CGAL-3D" ?
*this << "(echo \"CGAL-3D\")";
char inbuf[10];
std::size_t retread=::read(in, inbuf, 7);
(void)retread;
if (std::strncmp(inbuf, "started", 7) == 0)
{
// std::cerr << "You still have a .geomview file with the\n"
// << "(echo \"started\") command. Note that this is not\n"
// << "compulsory anymore, since CGAL 2.3" << std::endl;
// Then the next one is supposed to be CGAL-3D.
retread=::read(in, inbuf, 7);
(void)retread;
if (std::strncmp(inbuf, "CGAL-3D", 7) != 0)
std::cerr << "Unexpected string from Geomview !" << std::endl;
}
else if (std::strncmp(inbuf, "CGAL-3D", 7) == 0)
{
// std::cerr << "Good, you don't have a .geomview file with the\n"
// << "(echo \"started\") command" << std::endl;
}
else
{
std::cerr << "Unexcepted string from Geomview at initialization!\n"
<< "Going on nevertheless !" << std::endl;
}
#else
// Old original version
char inbuf[10];
// Waits for "started" from the .geomview file.
retread=::read(in, inbuf, 7);
(void)retread;
#endif
std::cout << "done." << std::endl;
(*this) << "(normalization g* none)(bbox-draw g* no)";
}
}
CGAL_INLINE_FUNCTION
void
Geomview_stream::pickplane(const Bbox_3 &bbox)
{
bool bin_bak = set_binary_mode();
(*this) << "(geometry pickplane {QUAD BINARY\n"
<< 1
// here are the four corners
<< bbox.xmin() << bbox.ymin() << bbox.zmin()
<< bbox.xmin() << bbox.ymax() << bbox.zmin()
<< bbox.xmax() << bbox.ymax() << bbox.zmin()
<< bbox.xmax() << bbox.ymin() << bbox.zmin()
// close the text bracket
<< "}) (pickable pickplane no)";
set_ascii_mode(bin_bak);
}
CGAL_INLINE_FUNCTION
void
Geomview_stream::clear()
{
(*this) << "(delete World)";
id.clear();
}
CGAL_INLINE_FUNCTION
void
Geomview_stream::look_recenter()
{
(*this) << "(look-recenter World)";
}
CGAL_INLINE_FUNCTION
Geomview_stream&
Geomview_stream::operator<<(const std::string & s)
{
if ((int)s.length() != ::write(out, s.data(), s.length())) {
CGAL_error_msg( "write problem in the pipe while sending data to geomview" );
}
trace(s);
return *this;
}
CGAL_INLINE_FUNCTION
Geomview_stream&
Geomview_stream::operator<<(int i)
{
// Depending on the mode chosen
if (get_binary_mode()) {
// we write raw binary data to the stream.
int num = i;
I_swap_to_big_endian(num);
std::size_t retwrite=::write(out, (char*)&num, sizeof(num));
(void)retwrite;
trace(i);
} else {
// transform the int in a character sequence and put whitespace around
std::ostringstream str;
str << i << ' ' << std::ends;
*this << str.str().c_str();
}
return *this;
}
CGAL_INLINE_FUNCTION
Geomview_stream&
Geomview_stream::operator<<(unsigned int i)
{
// Depending on the mode chosen
if (get_binary_mode()) {
// we write raw binary data to the stream.
unsigned int num = i;
I_swap_to_big_endian(num);
std::size_t retwrite=::write(out, (char*)&num, sizeof(num));
(void)retwrite;
trace(i);
} else {
// transform the int in a character sequence and put whitespace around
std::ostringstream str;
str << i << ' ' << std::ends;
*this << str.str().c_str();
}
return *this;
}
CGAL_INLINE_FUNCTION
Geomview_stream&
Geomview_stream::operator<<(long i)
{
return operator<<((int) i);
}
CGAL_INLINE_FUNCTION
Geomview_stream&
Geomview_stream::operator<<(unsigned long i)
{
return operator<<((unsigned int) i);
}
CGAL_INLINE_FUNCTION
Geomview_stream&
Geomview_stream::operator<<(double d)
{
float f = float(d);
if (get_binary_mode()) {
float num = float(d);
I_swap_to_big_endian(num);
std::size_t retwrite= ::write(out, (char*)&num, sizeof(num));
(void)retwrite;
trace(f);
} else {
// 'copy' the float in a string and append a blank
std::ostringstream str;
str << f << ' ' << std::ends;
*this << str.str().c_str();
}
return *this;
}
CGAL_INLINE_FUNCTION
Geomview_stream&
operator<<(Geomview_stream &gv, const Bbox_2 &bbox)
{
bool ascii_bak = gv.set_ascii_mode();
gv << "(geometry " << gv.get_new_id("Bbox")
<< " {VECT 1 5 0 5 0 ";
// here are the four corners
gv << bbox.xmin() << bbox.ymin() << 0.0
<< bbox.xmin() << bbox.ymax() << 0.0
<< bbox.xmax() << bbox.ymax() << 0.0
<< bbox.xmax() << bbox.ymin() << 0.0
<< bbox.xmin() << bbox.ymin() << 0.0;
// close the text bracket
gv << "})";
gv.set_ascii_mode(ascii_bak);
return gv;
}
CGAL_INLINE_FUNCTION
Geomview_stream&
operator<<(Geomview_stream &gv, const Bbox_3 &bbox)
{
bool ascii_bak = gv.set_ascii_mode();
gv << "(geometry " << gv.get_new_id("Bbox")
<< " {appearance {material {edgecolor "
<< gv.ecr() << gv.ecg() << gv.ecb() << "}}{SKEL 8 4 "
// here are the corners
<< bbox.xmin() << bbox.ymin() << bbox.zmin()
<< bbox.xmin() << bbox.ymax() << bbox.zmin()
<< bbox.xmax() << bbox.ymax() << bbox.zmin()
<< bbox.xmax() << bbox.ymin() << bbox.zmin()
<< bbox.xmax() << bbox.ymin() << bbox.zmax()
<< bbox.xmax() << bbox.ymax() << bbox.zmax()
<< bbox.xmin() << bbox.ymax() << bbox.zmax()
<< bbox.xmin() << bbox.ymin() << bbox.zmax()
<< "10 0 1 2 3 4 5 6 7 0 3\n"
<< "2 1 6\n"
<< "2 2 5\n"
<< "2 4 7\n"
// close the text bracket
<< "}})";
gv.set_ascii_mode(ascii_bak);
return gv;
}
CGAL_INLINE_FUNCTION
void
Geomview_stream::set_bg_color(const Color &c)
{
bool ascii_bak = set_ascii_mode();
*this << "(backcolor \"Camera\" "
<< double(c.r())/255.0
<< double(c.g())/255.0
<< double(c.b())/255.0
<< ")";
set_ascii_mode(ascii_bak);
}
CGAL_INLINE_FUNCTION
Geomview_stream&
Geomview_stream::operator<<(const Color &c)
{
vertex_color = edge_color = face_color = c;
return (*this);
}
CGAL_INLINE_FUNCTION
Color
Geomview_stream::get_vertex_color() const
{
return vertex_color;
}
CGAL_INLINE_FUNCTION
Color
Geomview_stream::get_edge_color() const
{
return edge_color;
}
CGAL_INLINE_FUNCTION
Color
Geomview_stream::get_face_color() const
{
return face_color;
}
CGAL_INLINE_FUNCTION
Color
Geomview_stream::set_vertex_color(const Color &c)
{
Color old = vertex_color;
vertex_color = c;
return old;
}
CGAL_INLINE_FUNCTION
Color
Geomview_stream::set_edge_color(const Color &c)
{
Color old = edge_color;
edge_color = c;
return old;
}
CGAL_INLINE_FUNCTION
Color
Geomview_stream::set_face_color(const Color &c)
{
Color old = face_color;
face_color = c;
return old;
}
CGAL_INLINE_FUNCTION
double
Geomview_stream::vcr() const
{
return double(vertex_color.r())/255.0;
}
CGAL_INLINE_FUNCTION
double
Geomview_stream::vcg() const
{
return double(vertex_color.g())/255.0;
}
CGAL_INLINE_FUNCTION
double
Geomview_stream::vcb() const
{
return double(vertex_color.b())/255.0;
}
CGAL_INLINE_FUNCTION
double
Geomview_stream::ecr() const
{
return double(edge_color.r())/255.0;
}
CGAL_INLINE_FUNCTION
double
Geomview_stream::ecg() const
{
return double(edge_color.g())/255.0;
}
CGAL_INLINE_FUNCTION
double
Geomview_stream::ecb() const
{
return double(edge_color.b())/255.0;
}
CGAL_INLINE_FUNCTION
double
Geomview_stream::fcr() const
{
return double(face_color.r())/255.0;
}
CGAL_INLINE_FUNCTION
double
Geomview_stream::fcg() const
{
return double(face_color.g())/255.0;
}
CGAL_INLINE_FUNCTION
double
Geomview_stream::fcb() const
{
return double(face_color.b())/255.0;
}
CGAL_INLINE_FUNCTION
void
Geomview_stream::frame(const Bbox_3 &bbox)
{
(*this) << bbox << "(look-recenter g0 c0)";
}
CGAL_INLINE_FUNCTION
Geomview_stream&
Geomview_stream::operator>>(char *expr)
{
// Skip whitespaces
do {
std::size_t retread=::read(in, expr, 1);
(void)retread;
} while (expr[0] != '(');
int pcount = 1;
int i = 1;
while (1) {
std::size_t retread=::read(in, &expr[i], 1);
(void)retread;
if (expr[i] == ')'){
pcount--;
} else if (expr[i] == '('){
pcount++;
}
if (pcount == 0){
expr[i+1]='\0';
break; // we encountered a balanced number of parantheses
}
i++;
}
return *this;
}
// Parse a Lisp expression, return a pointer to the beginning of the
// nth subexpression, and terminate it by '\0'.
// It's either a word terminated by ' ' or ')', or a well parenthesed
// expression, or a quoted "string".
CGAL_INLINE_FUNCTION
char*
Geomview_stream::nth(char* s, int count)
{
s++; // skip first character (always a parenthesis)
// Skip "count" words.
for(; count != 0; count--) {
while (*s == ' ') // skip whitespaces
s++;
s++;
while (*s != ' ') // skip a word
s++;
}
while (*s == ' ') // skip whitespaces
s++;
// Now we have the beginning of the searched sub-expression.
int j = 1;
if (*s == '(') // Case of a well-parenthesed expression.
for (int pcount = 1; pcount != 0;) {
if (s[j] == ')') pcount--;
if (s[j] == '(') pcount++;
j++;
}
else if (*s == '"') { // Case of a quoted "string".
while (s[j] != '"')
j++;
j++;
}
else // Case of a word terminated by ' ' or ')'.
while (s[j] != ' ' && s[j] != ')')
j++;
s[j] = '\0';
return s;
}
CGAL_INLINE_FUNCTION
void
Geomview_stream::parse_point(const char* pickpoint,
double &x, double &y, double &z, double &w)
{
std::stringstream ss;
ss << pickpoint << std::ends;
char parenthesis;
ss >> parenthesis >> x >> y >> z >> w;
}
CGAL_INLINE_FUNCTION
std::string
Geomview_stream::get_new_id(const std::string & s)
{
std::ostringstream str;
str << s << id[s]++ << std::ends;
return str.str();
}
} //namespace CGAL
#else
#ifndef CGAL_HEADER_ONLY
// Add a dummy symbol to prevent warnings of empty translation unit.
namespace CGAL {
namespace {
int dummy;
}
} //namespace CGAL
#endif
#endif // CGAL_USE_GEOMVIEW