//
// ********************************************************************
// * License and Disclaimer                                           *
// *                                                                  *
// * The  Geant4 software  is  copyright of the Copyright Holders  of *
// * the Geant4 Collaboration.  It is provided  under  the terms  and *
// * conditions of the Geant4 Software License,  included in the file *
// * LICENSE and available at  http://cern.ch/geant4/license .  These *
// * include a list of copyright holders.                             *
// *                                                                  *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work  make  any representation or  warranty, express or implied, *
// * regarding  this  software system or assume any liability for its *
// * use.  Please see the license in the file  LICENSE  and URL above *
// * for the full disclaimer and the limitation of liability.         *
// *                                                                  *
// * This  code  implementation is the result of  the  scientific and *
// * technical work of the GEANT4 collaboration.                      *
// * By using,  copying,  modifying or  distributing the software (or *
// * any work based  on the software)  you  agree  to acknowledge its *
// * use  in  resulting  scientific  publications,  and indicate your *
// * acceptance of all terms of the Geant4 Software license.          *
// ********************************************************************
//
//
// $Id: G4VisCommandsViewerSet.cc,v 1.49 2007/07/10 17:51:54 allison Exp $
// GEANT4 tag $Name:  $

// /vis/viewer/set commands - John Allison  16th May 2000

#include "G4VisCommandsViewerSet.hh"

#include "G4UIcommand.hh"
#include "G4UIcmdWithAString.hh"
#include "G4UIcmdWithABool.hh"
#include "G4UIcmdWithAnInteger.hh"
#include "G4UIcmdWithADouble.hh"
#include "G4UnitsTable.hh"
#include "G4VisManager.hh"
#include "G4Polyhedron.hh"

#include <sstream>
#include <cctype>

G4VisCommandsViewerSet::G4VisCommandsViewerSet ():
  fLightsVector    (G4ThreeVector(1.,1.,1.)),
  fUpVector        (G4ThreeVector(0.,1.,0.)),
  fViewpointVector (G4ThreeVector(0.,0.,1.))
{
  G4bool omitable;
  G4UIparameter* parameter;

  fpCommandAll = new G4UIcmdWithAString ("/vis/viewer/set/all",this);
  fpCommandAll->SetGuidance
    ("Copies view parameters.");
  fpCommandAll->SetGuidance
    ("Copies view parameters (except the autoRefresh status) from"
     "\nfrom-viewer to current viewer.");
  fpCommandAll->SetParameterName ("from-viewer-name",omitable = false);

  fpCommandAutoRefresh = new G4UIcmdWithABool
    ("/vis/viewer/set/autoRefresh",this);
  fpCommandAutoRefresh->SetGuidance("Sets auto-refresh.");
  fpCommandAutoRefresh->SetGuidance
    ("If true, view is automatically refreshed after a change of"
     "\nview parameters.");
  fpCommandAutoRefresh->SetParameterName("auto-refresh",omitable = true);
  fpCommandAutoRefresh->SetDefaultValue(true);

  fpCommandAuxEdge = new G4UIcmdWithABool
    ("/vis/viewer/set/auxiliaryEdge",this);
  fpCommandAuxEdge->SetGuidance("Sets visibility of auxiliary edges");
  fpCommandAuxEdge->SetGuidance
    ("Auxiliary edges, i.e., those that are part of a curved surface,"
     "\nsometimes called soft edges, become visible/invisible.");
  fpCommandAuxEdge->SetParameterName("edge",omitable = true);
  fpCommandAuxEdge->SetDefaultValue(true);

  fpCommandBackground = new G4UIcommand
    ("/vis/viewer/set/background",this);
  fpCommandBackground->SetGuidance
    ("Set background colour and transparency (default black and opaque).");
  fpCommandBackground->SetGuidance
    ("Accepts (a) RGB triplet. e.g., \".3 .4 .5\", or"
     "\n(b) string such as \"white\", \"black\", \"grey\", \"red\"..."
     "\n(c) an additional number for opacity, e.g., \".3 .4 .5 .6\""
     "\n    or \"grey ! ! .6\" (note \"!\"'s for unused green and blue parameters),"
     "\n    e.g. \"! ! ! 0.\" for a transparent background.");
  parameter = new G4UIparameter("red_or_string", 's', omitable = true);
  parameter -> SetDefaultValue ("0.");
  fpCommandBackground -> SetParameter (parameter);
  parameter = new G4UIparameter("green", 'd', omitable = true);
  parameter -> SetDefaultValue (0.);
  fpCommandBackground -> SetParameter (parameter);
  parameter = new G4UIparameter ("blue", 'd', omitable = true);
  parameter -> SetDefaultValue (0.);
  fpCommandBackground -> SetParameter (parameter);
  parameter = new G4UIparameter ("opacity", 'd', omitable = true);
  parameter -> SetDefaultValue (1.);
  fpCommandBackground -> SetParameter (parameter);

  fpCommandCulling = new G4UIcommand("/vis/viewer/set/culling",this);
  fpCommandCulling->SetGuidance ("Set culling options.");
  fpCommandCulling->SetGuidance
    ("\"global\": enables/disables all other culling options.");
  fpCommandCulling->SetGuidance
    ("\"coveredDaughters\": culls, i.e., eliminates, volumes that would not"
     "\nbe seen because covered by ancester volumes in surface drawing mode,"
     "\nand then only if the ancesters are visible and opaque, and then only"
     "\nif no sections or cutaways are in operation.  Intended solely to"
     "\nimprove the speed of rendering visible volumes.");
  fpCommandCulling->SetGuidance
    ("\"invisible\": culls objects with the invisible attribute set.");
  fpCommandCulling->SetGuidance
    ("\"density\": culls volumes with density lower than threshold.  Useful"
     "\nfor eliminating \"container volumes\" with no physical correspondence,"
     "\nwhose material is usually air.  If this is selected, provide threshold"
     "\ndensity and unit (g/cm3 mg/cm3 or kg/m3)."
     );
  parameter = new G4UIparameter("culling-option",'s',omitable = false);
  parameter->SetParameterCandidates
    ("global coveredDaughters invisible density");
  fpCommandCulling->SetParameter(parameter);
  parameter = new G4UIparameter("action",'b',omitable = true);
  parameter->SetDefaultValue(1);
  fpCommandCulling->SetParameter(parameter);
  parameter = new G4UIparameter("density-threshold",'d',omitable = true);
  parameter->SetDefaultValue("0.01");
  fpCommandCulling->SetParameter(parameter);
  parameter = new G4UIparameter("unit",'s',omitable = true);
  parameter->SetParameterCandidates ("g/cm3, mg/cm3 kg/m3");
  parameter->SetDefaultValue("g/cm3");
  fpCommandCulling->SetParameter(parameter);

  fpCommandCutawayMode =
    new G4UIcmdWithAString ("/vis/viewer/set/cutawayMode", this);
  fpCommandCutawayMode->SetGuidance
    ("Sets cutaway mode - add (union) or multiply (intersection).");
  fpCommandCutawayMode->SetParameterName ("cutaway-mode",omitable = false);
  fpCommandCutawayMode->SetCandidates ("add union multiply intersection");
  fpCommandCutawayMode->SetDefaultValue("union");

  fpCommandEdge = new G4UIcmdWithABool("/vis/viewer/set/edge",this);
  fpCommandEdge->SetGuidance
    ("Edges become visible/invisible in surface mode.");
  fpCommandEdge->SetParameterName("edge",omitable = true);
  fpCommandEdge->SetDefaultValue(true);

  fpCommandExplodeFactor = new G4UIcommand
    ("/vis/viewer/set/explodeFactor", this);
  fpCommandExplodeFactor->SetGuidance
    ("Moves top-level drawn volumes by this factor from this centre.");
  parameter = new G4UIparameter("explodeFactor", 'd', omitable=true);
  parameter->SetParameterRange("explodeFactor>=1.");
  parameter->SetDefaultValue(1.);
  fpCommandExplodeFactor->SetParameter(parameter);
  parameter = new G4UIparameter("x",'d',omitable = true);
  parameter->SetDefaultValue  (0);
  parameter->SetGuidance      ("Coordinate of explode centre.");
  fpCommandExplodeFactor->SetParameter(parameter);
  parameter = new G4UIparameter("y",'d',omitable = true);
  parameter->SetDefaultValue  (0);
  parameter->SetGuidance      ("Coordinate of explode centre.");
  fpCommandExplodeFactor->SetParameter(parameter);
  parameter = new G4UIparameter("z",'d',omitable = true);
  parameter->SetDefaultValue  (0);
  parameter->SetGuidance      ("Coordinate of explode centre.");
  fpCommandExplodeFactor->SetParameter(parameter);
  parameter = new G4UIparameter("unit",'s',omitable = true);
  parameter->SetDefaultValue  ("m");
  parameter->SetGuidance      ("Unit of explode centre.");
  fpCommandExplodeFactor->SetParameter(parameter);

  fpCommandGlobalLineWidthScale = new G4UIcmdWithADouble
    ("/vis/viewer/set/globalLineWidthScale", this);
  fpCommandGlobalLineWidthScale->SetGuidance
    ("Multiplies line widths by this factor.");
  fpCommandGlobalLineWidthScale->
    SetParameterName("scale-factor", omitable=true);
  fpCommandGlobalLineWidthScale->SetDefaultValue(1.);

  fpCommandGlobalMarkerScale = new G4UIcmdWithADouble
    ("/vis/viewer/set/globalMarkerScale", this);
  fpCommandGlobalMarkerScale->SetGuidance
    ("Multiplies marker sizes by this factor.");
  fpCommandGlobalMarkerScale->
    SetParameterName("scale-factor", omitable=true);
  fpCommandGlobalMarkerScale->SetDefaultValue(1.);

  fpCommandHiddenEdge =
    new G4UIcmdWithABool("/vis/viewer/set/hiddenEdge",this);
  fpCommandHiddenEdge->SetGuidance
    ("Edges become hidden/seen in wireframe or surface mode.");
  fpCommandHiddenEdge->SetParameterName("hidden-edge",omitable = true);
  fpCommandHiddenEdge->SetDefaultValue(true);

  fpCommandHiddenMarker =
    new G4UIcmdWithABool("/vis/viewer/set/hiddenMarker",this);
  fpCommandHiddenMarker->SetGuidance
    ("If true, closer objects hide markers. Otherwise, markers always show.");
  fpCommandHiddenMarker->SetParameterName("hidden-marker",omitable = true);
  fpCommandHiddenMarker->SetDefaultValue(true);

  fpCommandLightsMove = new G4UIcmdWithAString
    ("/vis/viewer/set/lightsMove",this);
  fpCommandLightsMove->SetGuidance
    ("Lights move with camera or with object");
  fpCommandLightsMove->SetParameterName("lightsMove",omitable = false);
  fpCommandLightsMove->SetCandidates
    ("cam camera with-camera obj object with-object");

  fpCommandLightsThetaPhi = new G4UIcommand
    ("/vis/viewer/set/lightsThetaPhi", this);
  fpCommandLightsThetaPhi->SetGuidance
    ("Set direction from target to lights.");
  parameter = new G4UIparameter("theta", 'd', omitable = true);
  parameter -> SetDefaultValue(60.);
  fpCommandLightsThetaPhi -> SetParameter (parameter);
  parameter = new G4UIparameter("phi", 'd', omitable = true);
  parameter -> SetDefaultValue(45.);
  fpCommandLightsThetaPhi -> SetParameter (parameter);
  parameter = new G4UIparameter ("unit", 's', omitable = true);
  parameter -> SetDefaultValue ("deg");
  fpCommandLightsThetaPhi -> SetParameter (parameter);

  fpCommandLightsVector = new G4UIcommand
    ("/vis/viewer/set/lightsVector", this);
  fpCommandLightsVector->SetGuidance
    ("Set direction from target to lights.");
  parameter = new G4UIparameter("x", 'd', omitable = true);
  parameter -> SetDefaultValue (1);
  fpCommandLightsVector -> SetParameter (parameter);
  parameter = new G4UIparameter("y", 'd', omitable = true);
  parameter -> SetDefaultValue (1);
  fpCommandLightsVector -> SetParameter (parameter);
  parameter = new G4UIparameter ("z", 'd', omitable = true);
  parameter -> SetDefaultValue (1);
  fpCommandLightsVector -> SetParameter (parameter);

  fpCommandLineSegments = new G4UIcmdWithAnInteger
    ("/vis/viewer/set/lineSegmentsPerCircle",this);
  fpCommandLineSegments->SetGuidance
    ("Set number of sides per circle for polygon/polyhedron drawing.");
  fpCommandLineSegments->SetGuidance
 ("Refers to graphical representation of objects with curved lines/surfaces.");
  fpCommandLineSegments->SetParameterName("line-segments",omitable = true);
  fpCommandLineSegments->SetDefaultValue(24);

  fpCommandPicking = new G4UIcmdWithABool
    ("/vis/viewer/set/picking",this);
  fpCommandPicking->SetGuidance("Sets picking, if available.");
  fpCommandPicking->SetGuidance
    ("If true, view is set up for picking, if available."
     "\nFor required actions, watch for instructions for viewer.");
  fpCommandPicking->SetParameterName("picking",omitable = true);
  fpCommandPicking->SetDefaultValue(true);

  fpCommandProjection = new G4UIcommand("/vis/viewer/set/projection",this);
  fpCommandProjection->SetGuidance
    ("Orthogonal or perspective projection.");
  parameter = new G4UIparameter("projection",'s',omitable = true);
  parameter->SetParameterCandidates("o orthogonal p perspective");
  parameter->SetDefaultValue("orthogonal");
  fpCommandProjection->SetParameter(parameter);
  parameter = new G4UIparameter("field-half-angle",'d',omitable = true);
  parameter->SetDefaultValue(30.);
  fpCommandProjection->SetParameter(parameter);
  parameter = new G4UIparameter("unit",'s',omitable = true);
  parameter->SetDefaultValue("deg");
  fpCommandProjection->SetParameter(parameter);

  fpCommandSectionPlane = new G4UIcommand("/vis/viewer/set/sectionPlane",this);
  fpCommandSectionPlane -> SetGuidance
    ("Set plane for drawing section (DCUT).");
  fpCommandSectionPlane -> SetGuidance
    ("E.g., for a y-z plane at x = 1 cm:"
     "\n\"/vis/viewer/set/sectionPlane on 1 0 0 cm 1 0 0\"."
     "\nTo turn off: /vis/viewer/set/sectionPlane off");
  parameter  =  new G4UIparameter("Selector",'c',true);
  parameter  -> SetDefaultValue  ("on");
  fpCommandSectionPlane->SetParameter(parameter);
  parameter  =  new G4UIparameter("x",'d',omitable = true);
  parameter  -> SetDefaultValue  (0);
  parameter  -> SetGuidance      ("Coordinate of point on the plane.");
  fpCommandSectionPlane->SetParameter(parameter);
  parameter  =  new G4UIparameter("y",'d',omitable = true);
  parameter  -> SetDefaultValue  (0);
  parameter  -> SetGuidance      ("Coordinate of point on the plane.");
  fpCommandSectionPlane->SetParameter(parameter);
  parameter  =  new G4UIparameter("z",'d',omitable = true);
  parameter  -> SetDefaultValue  (0);
  parameter  -> SetGuidance      ("Coordinate of point on the plane.");
  fpCommandSectionPlane->SetParameter(parameter);
  parameter  =  new G4UIparameter("unit",'s',omitable = true);
  parameter  -> SetDefaultValue  ("m");
  parameter  -> SetGuidance      ("Unit of point on the plane.");
  fpCommandSectionPlane->SetParameter(parameter);
  parameter  =  new G4UIparameter("nx",'d',omitable = true);
  parameter  -> SetDefaultValue  (1);
  parameter  -> SetGuidance      ("Component of plane normal.");
  fpCommandSectionPlane->SetParameter(parameter);
  parameter  =  new G4UIparameter("ny",'d',omitable = true);
  parameter  -> SetDefaultValue  (0);
  parameter  -> SetGuidance      ("Component of plane normal.");
  fpCommandSectionPlane->SetParameter(parameter);
  parameter  =  new G4UIparameter("nz",'d',omitable = true);
  parameter  -> SetDefaultValue  (0);
  parameter  -> SetGuidance      ("Component of plane normal.");
  fpCommandSectionPlane->SetParameter(parameter);

  fpCommandStyle = new G4UIcmdWithAString ("/vis/viewer/set/style",this);
  fpCommandStyle->SetGuidance
    ("Set style of drawing - w[ireframe] or s[urface].");
  fpCommandStyle->SetGuidance 
    ("(Hidden line drawing is controlled by \"/vis/viewer/set/hiddenEdge\".)");
  fpCommandStyle->SetParameterName ("style",omitable = false);

  fpCommandUpThetaPhi = new G4UIcommand
    ("/vis/viewer/set/upThetaPhi", this);
  fpCommandUpThetaPhi -> SetGuidance ("Set up vector.");
  fpCommandUpThetaPhi -> SetGuidance
    ("Viewer will attempt always to show this direction upwards.");
  parameter = new G4UIparameter("theta", 'd', omitable = true);
  parameter -> SetDefaultValue (90.);
  fpCommandUpThetaPhi -> SetParameter (parameter);
  parameter = new G4UIparameter("phi", 'd', omitable = true);
  parameter -> SetDefaultValue (90.);
  fpCommandUpThetaPhi -> SetParameter (parameter);
  parameter = new G4UIparameter ("unit", 's', omitable = true);
  parameter -> SetDefaultValue ("deg");
  fpCommandUpThetaPhi -> SetParameter (parameter);

  fpCommandUpVector = new G4UIcommand
    ("/vis/viewer/set/upVector", this);
  fpCommandUpVector -> SetGuidance ("Set up vector.");
  fpCommandUpVector -> SetGuidance
    ("Viewer will attempt always to show this direction upwards.");
  parameter = new G4UIparameter("x", 'd', omitable = true);
  parameter -> SetDefaultValue (0.);
  fpCommandUpVector -> SetParameter (parameter);
  parameter = new G4UIparameter("y", 'd', omitable = true);
  parameter -> SetDefaultValue (1.);
  fpCommandUpVector -> SetParameter (parameter);
  parameter = new G4UIparameter ("z", 'd', omitable = true);
  parameter -> SetDefaultValue (0.);
  fpCommandUpVector -> SetParameter (parameter);

  fpCommandViewpointThetaPhi = new G4UIcommand
    ("/vis/viewer/set/viewpointThetaPhi", this);
  fpCommandViewpointThetaPhi -> SetGuidance
    ("Set direction from target to camera.");
  fpCommandViewpointThetaPhi -> SetGuidance
  ("Also changes lightpoint direction if lights are set to move with camera.");
  parameter = new G4UIparameter("theta", 'd', omitable = true);
  parameter -> SetDefaultValue (60.);
  fpCommandViewpointThetaPhi -> SetParameter (parameter);
  parameter = new G4UIparameter("phi", 'd', omitable = true);
  parameter -> SetDefaultValue (45.);
  fpCommandViewpointThetaPhi -> SetParameter (parameter);
  parameter = new G4UIparameter ("unit", 's', omitable = true);
  parameter -> SetDefaultValue ("deg");
  fpCommandViewpointThetaPhi -> SetParameter (parameter);

  fpCommandViewpointVector = new G4UIcommand
    ("/vis/viewer/set/viewpointVector", this);
  fpCommandViewpointVector -> SetGuidance
    ("Set direction from target to camera.");
  fpCommandViewpointVector -> SetGuidance
  ("Also changes lightpoint direction if lights are set to move with camera.");
  parameter = new G4UIparameter("x", 'd', omitable = true);
  parameter -> SetDefaultValue (1.);
  fpCommandViewpointVector -> SetParameter (parameter);
  parameter = new G4UIparameter("y", 'd', omitable = true);
  parameter -> SetDefaultValue (1.);
  fpCommandViewpointVector -> SetParameter (parameter);
  parameter = new G4UIparameter ("z", 'd', omitable = true);
  parameter -> SetDefaultValue (1.);
  fpCommandViewpointVector -> SetParameter (parameter);
}

G4VisCommandsViewerSet::~G4VisCommandsViewerSet() {
  delete fpCommandAll;
  delete fpCommandAuxEdge;
  delete fpCommandAutoRefresh;
  delete fpCommandBackground;
  delete fpCommandCulling;
  delete fpCommandCutawayMode;
  delete fpCommandEdge;
  delete fpCommandExplodeFactor;
  delete fpCommandGlobalLineWidthScale;
  delete fpCommandGlobalMarkerScale;
  delete fpCommandHiddenEdge;
  delete fpCommandHiddenMarker;
  delete fpCommandLineSegments;
  delete fpCommandLightsMove;
  delete fpCommandLightsThetaPhi;
  delete fpCommandLightsVector;
  delete fpCommandPicking;
  delete fpCommandProjection;
  delete fpCommandSectionPlane;
  delete fpCommandStyle;
  delete fpCommandUpThetaPhi;
  delete fpCommandUpVector;
  delete fpCommandViewpointThetaPhi;
  delete fpCommandViewpointVector;
}

G4String G4VisCommandsViewerSet::GetCurrentValue(G4UIcommand*) {
  return "";
}

void G4VisCommandsViewerSet::SetNewValue
(G4UIcommand* command,G4String newValue) {

  G4VisManager::Verbosity verbosity = fpVisManager->GetVerbosity();

  G4VViewer* currentViewer = fpVisManager->GetCurrentViewer();
  if (!currentViewer) {
    if (verbosity >= G4VisManager::errors) {
      G4cout << 
	"ERROR: G4VisCommandsViewerSet::SetNewValue: no current viewer."
	     << G4endl;
    }
    return;
  }

  G4ViewParameters vp = currentViewer->GetViewParameters();

  if (command == fpCommandAll) {
    G4VViewer* fromViewer = fpVisManager->GetViewer(newValue);
    if (!fromViewer) {
      if (verbosity >= G4VisManager::errors) {
	G4cout <<
	  "ERROR: G4VisCommandsViewerSet::SetNewValue: all:"
	  "\n  unrecognised from-viewer."
	       << G4endl;
      }
      return;
    }
    if (fromViewer == currentViewer) {
      if (verbosity >= G4VisManager::warnings) {
      G4cout <<
	"WARNING: G4VisCommandsViewerSet::SetNewValue: all:"
	"\n  from-viewer and current viewer are identical."
	     << G4endl;
      }
      return;
    }
    // Copy view parameters except for autoRefresh...
    G4bool currentAutoRefresh =
      currentViewer->GetViewParameters().IsAutoRefresh();
    vp = fromViewer->GetViewParameters();
    vp.SetAutoRefresh(currentAutoRefresh);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "View parameters of viewer \"" << currentViewer->GetName()
	     << "\"\n  set to those of viewer \"" << fromViewer->GetName()
	     << "\"."
	     << G4endl;
    }
  }

  else if (command == fpCommandAutoRefresh) {
    G4bool autoRefresh = G4UIcommand::ConvertToBool(newValue);
    vp.SetAutoRefresh(autoRefresh);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Views will ";
      if (!vp.IsAutoRefresh()) G4cout << "not ";
      G4cout << "be automatically refreshed after a change of view parameters."
	     << G4endl;
    }
    if (!vp.IsAutoRefresh()) {
      currentViewer->SetViewParameters(vp);
      return;  // Avoid a refresh id auto-refresh has been set to off...
    }  // ...otherwise take normal action.
  }

  else if (command == fpCommandAuxEdge) {
    vp.SetAuxEdgeVisible(G4UIcommand::ConvertToBool(newValue));
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Auxiliary edges will ";
      if (!vp.IsAuxEdgeVisible()) G4cout << "not ";
      G4cout << "be visible." << G4endl;
    }
  }

  else if (command == fpCommandBackground) {
    G4String redOrString;
    G4double green, blue, opacity;
    std::istringstream iss(newValue);
    iss >> redOrString >> green >> blue >> opacity;
    G4Colour colour(0.,0.,0.);  // Default black and opaque.
    const size_t iPos0 = 0;
    if (std::isalpha(redOrString[iPos0])) {
      G4Colour::GetColour(redOrString, colour); // Remains default (black) if
						// not found.
    } else {
      colour = G4Colour(G4UIcommand::ConvertTo3Vector(newValue));
    }
    colour = G4Colour(colour.GetRed(), colour.GetGreen(), colour.GetBlue(), opacity);
    vp.SetBackgroundColour(colour);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Background colour "
	     << vp.GetBackgroundColour()
	     << " requested."
	     << G4endl;
    }
  }

  else if (command == fpCommandCulling) {
    G4String cullingOption, stringFlag, unit;
    G4double density;
    std::istringstream is (newValue);
    is >> cullingOption >> stringFlag >> density >> unit;
    G4bool boolFlag = G4UIcommand::ConvertToBool(stringFlag);
    if (cullingOption == "global") {
      vp.SetCulling(boolFlag);
      if (verbosity >= G4VisManager::confirmations) {
	G4cout <<
	  "G4VisCommandsViewerSet::SetNewValue: culling: global culling flag"
	  " set to " << G4UIcommand::ConvertToString(boolFlag) <<
	  ".\n  Does not change specific culling flags."
	       << G4endl;
      }
    }
    else if (cullingOption == "coveredDaughters") {
      vp.SetCullingCovered(boolFlag);
      if (verbosity >= G4VisManager::confirmations) {
	G4cout <<
	  "G4VisCommandsViewerSet::SetNewValue: culling: culling covered"
	  "\n  daughters flag set to "
	       << G4UIcommand::ConvertToString(boolFlag) <<
	  ".  Daughters covered by opaque mothers"
	  "\n  will be culled, i.e., not drawn, if this flag is true."
	  "\n  Note: this is only effective in surface drawing style,"
	  "\n  and then only if the volumes are visible and opaque, and then"
	  "\n  only if no sections or cutaways are in operation."
	       << G4endl;
      }
    }
    else if (cullingOption == "invisible") {
      vp.SetCullingInvisible(boolFlag);
      if (verbosity >= G4VisManager::confirmations) {
	G4cout <<
	  "G4VisCommandsViewerSet::SetNewValue: culling: culling invisible"
	  "\n  flag set to "
	       << boolFlag << G4UIcommand::ConvertToString(boolFlag) <<
	  ".  Volumes marked invisible will be culled,"
	  "\n  i.e., not drawn, if this flag is true."
	       << G4endl;
      }
    }
    else if (cullingOption == "density") {
      vp.SetDensityCulling(boolFlag);
      if (boolFlag) {
	density *= G4UnitDefinition::GetValueOf(unit);
	vp.SetVisibleDensity(density);
      }
      else {
	density = vp.GetVisibleDensity();
      }
      if (verbosity >= G4VisManager::confirmations) {
	G4cout <<
	  "G4VisCommandsViewerSet::SetNewValue: culling: culling by density"
	  "\n  flag set to " << G4UIcommand::ConvertToString(boolFlag) <<
	  ".  Volumes with density less than " <<
	  G4BestUnit(density,"Volumic Mass") <<
	  "\n  will be culled, i.e., not drawn, if this flag is true."
	       << G4endl;
      }
    }
    else {
      if (verbosity >= G4VisManager::errors) {
	G4cout <<
	  "ERROR: G4VisCommandsViewerSet::SetNewValue: culling:"
	  "\n  option not recognised."
	       << G4endl;
      }
    }
  }

  else if (command == fpCommandCutawayMode) {
    if (newValue == "add" || newValue == "union")
      vp.SetCutawayMode(G4ViewParameters::cutawayUnion);
    if (newValue == "multiply" || newValue == "intersection")
      vp.SetCutawayMode(G4ViewParameters::cutawayIntersection);
 
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Cutaway mode set to ";
      if (vp.GetCutawayMode() == G4ViewParameters::cutawayUnion)
	G4cout << "cutawayUnion";
      if (vp.GetCutawayMode() == G4ViewParameters::cutawayIntersection)
	G4cout << "cutawayIntersection";
      G4cout << G4endl;
    }
  }

  else if (command == fpCommandEdge) {
    G4ViewParameters::DrawingStyle existingStyle = vp.GetDrawingStyle();
    if (G4UIcommand::ConvertToBool(newValue)) {
      switch (existingStyle) {
      case G4ViewParameters::wireframe:
	break;
      case G4ViewParameters::hlr:
	break;
      case G4ViewParameters::hsr:
	vp.SetDrawingStyle(G4ViewParameters::hlhsr);
        break;
      case G4ViewParameters::hlhsr:
        break;
      }
    }
    else {
      switch (existingStyle) {
      case G4ViewParameters::wireframe:
	break;
      case G4ViewParameters::hlr:
	break;
      case G4ViewParameters::hsr:
	break;
      case G4ViewParameters::hlhsr:
	vp.SetDrawingStyle(G4ViewParameters::hsr);
	break;
      }
    }
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Drawing style of viewer \"" << currentViewer->GetName()
	     << "\" set to " << vp.GetDrawingStyle()
	     << G4endl;
    }
  }

  else if (command == fpCommandExplodeFactor) {
    G4double explodeFactor, x, y, z;
    G4String unitString;
    std::istringstream is (newValue);
    is >> explodeFactor >> x >> y >> z >> unitString;
    G4double unit = G4UIcommand::ValueOf(unitString);
    vp.SetExplodeFactor(explodeFactor);
    vp.SetExplodeCentre(G4Point3D(x * unit, y * unit, z * unit));
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Explode factor changed to " << vp.GetExplodeFactor()
	     << " from centre " << vp.GetExplodeCentre()
	     << G4endl;
    }
  }

  else if (command == fpCommandGlobalLineWidthScale) {
    G4double globalLineWidthScale
      = fpCommandGlobalLineWidthScale->GetNewDoubleValue(newValue);
    vp.SetGlobalLineWidthScale(globalLineWidthScale);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Global Line Width Scale changed to "
	     << vp.GetGlobalLineWidthScale() << G4endl;
    }
  }

  else if (command == fpCommandGlobalMarkerScale) {
    G4double globalMarkerScale
      = fpCommandGlobalMarkerScale->GetNewDoubleValue(newValue);
    vp.SetGlobalMarkerScale(globalMarkerScale);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Global Marker Scale changed to "
	     << vp.GetGlobalMarkerScale() << G4endl;
    }
  }

  else if (command == fpCommandHiddenEdge) {
    G4ViewParameters::DrawingStyle existingStyle = vp.GetDrawingStyle();
    if (G4UIcommand::ConvertToBool(newValue)) {
      switch (existingStyle) {
      case G4ViewParameters::wireframe:
	vp.SetDrawingStyle(G4ViewParameters::hlr);
	break;
      case G4ViewParameters::hlr:
	break;
      case G4ViewParameters::hsr:
	vp.SetDrawingStyle(G4ViewParameters::hlhsr);
        break;
      case G4ViewParameters::hlhsr:
        break;
      }
    }
    else {
      switch (existingStyle) {
      case G4ViewParameters::wireframe:
	break;
      case G4ViewParameters::hlr:
	vp.SetDrawingStyle(G4ViewParameters::wireframe);
	break;
      case G4ViewParameters::hsr:
	break;
      case G4ViewParameters::hlhsr:
	vp.SetDrawingStyle(G4ViewParameters::hsr);
	break;
      }
    }
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Drawing style of viewer \"" << currentViewer->GetName()
	     << "\" set to " << vp.GetDrawingStyle()
	     << G4endl;
    }
  }

  else if (command == fpCommandHiddenMarker) {
    G4bool hidden = G4UIcommand::ConvertToBool(newValue);
    if (hidden) vp.SetMarkerHidden();
    else vp.SetMarkerNotHidden();
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Markers will ";
      if (vp.IsMarkerNotHidden()) G4cout << "not ";
      G4cout << "be hidden under solid objects." << G4endl;
    }
  }

  else if (command == fpCommandLightsMove) {
    G4String s (newValue);
    if (s.find("cam") != G4String::npos) vp.SetLightsMoveWithCamera(true);
    else if(s.find("obj") != G4String::npos) vp.SetLightsMoveWithCamera(false);
    else {
      if (verbosity >= G4VisManager::errors) {
	G4cout << "ERROR: \"" << newValue << "\" not recognised."
	"  Looking for \"cam\" or \"obj\" in string." << G4endl;
      }
    }
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Lights move with ";
      if (vp.GetLightsMoveWithCamera())
	G4cout << "camera (object appears to rotate).";
      else G4cout << "object (the viewer appears to be moving).";
      G4cout << G4endl;
    }
  }

  else if (command == fpCommandLightsThetaPhi) {
    G4double theta, phi;
    ConvertToDoublePair(newValue, theta, phi);
    G4double x = std::sin (theta) * std::cos (phi);
    G4double y = std::sin (theta) * std::sin (phi);
    G4double z = std::cos (theta);
    fLightsVector = G4ThreeVector (x, y, z);
    vp.SetLightpointDirection(fLightsVector);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Lights direction set to "
	     << vp.GetLightpointDirection() << G4endl;
    }
  }

  else if (command == fpCommandLightsVector) {
    fLightsVector = G4UIcommand::ConvertTo3Vector(newValue);
    vp.SetLightpointDirection(fLightsVector);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Lights direction set to "
	     << vp.GetLightpointDirection() << G4endl;
    }
  }

  else if (command == fpCommandLineSegments) {
    G4int nSides = G4UIcommand::ConvertToInt(newValue);
    nSides = vp.SetNoOfSides(nSides);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout <<
	"Number of line segements per circle in polygon approximation is "
	     << nSides << G4endl;
    }
  }

  else if (command == fpCommandPicking) {
    vp.SetPicking(G4UIcommand::ConvertToBool(newValue));
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Picking ";
      if (vp.IsPicking()) G4cout << "requested.";
      else G4cout << "inhibited.";
      G4cout << G4endl;
    }
  }

  else if (command == fpCommandProjection) {
    G4double fieldHalfAngle;
    const size_t iPos0 = 0;
    if (newValue[iPos0] == 'o') {  // "orthogonal"
      fieldHalfAngle = 0.;
    }
    else if (newValue[iPos0] == 'p') {  // "perspective"
      G4String dummy;
      G4String unit;
      std::istringstream is (newValue);
      is >> dummy >> fieldHalfAngle >> unit;
      fieldHalfAngle *= G4UIcommand::ValueOf(unit);
      if (fieldHalfAngle > 89.5 * deg || fieldHalfAngle <= 0.0) {
	if (verbosity >= G4VisManager::errors) {
	  G4cout <<
	    "ERROR: Field half angle should be 0 < angle <= 89.5 degrees.";
	  G4cout << G4endl;
	}
	return;
      }
    }
    else {
      if (verbosity >= G4VisManager::errors) {
	G4cout << "ERROR: \"" << newValue << "\" not recognised."
	  "  Looking for 'o' or 'p' first character." << G4endl;
      }
      return;
    }
    vp.SetFieldHalfAngle(fieldHalfAngle);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Projection style of viewer \"" << currentViewer->GetName()
	     << "\" set to ";
      if (fieldHalfAngle == 0.) {
	G4cout << "orthogonal.";
      }
      else {
	G4cout << "perspective\n  with half angle " << fieldHalfAngle / deg
	       << " degrees.";
      }
      G4cout << G4endl;
    }
  }

  else if (command == fpCommandSectionPlane) {
    G4String choice, unit;
    G4double x, y, z, nx, ny, nz;
    std::istringstream is (newValue);
    is >> choice >> x >> y >> z >> unit >> nx >> ny >> nz;

    G4int iSelector = -1;
    if (choice.compareTo("off",G4String::ignoreCase) == 0 ||
	!G4UIcommand::ConvertToBool(choice)) iSelector = 0;
    if (choice.compareTo("on",G4String::ignoreCase) == 0 ||
	G4UIcommand::ConvertToBool(choice)) iSelector = 1;
    if (iSelector < 0) {
      if (verbosity >= G4VisManager::errors) {
	G4cout << "Choice not recognised (on/true or off/false)." << G4endl;
	G4cout << "Section drawing is currently: ";
	if (vp.IsSection ()) G4cout << "on";
	else                    G4cout << "off";
	G4cout << ".\nSection plane is currently: "
	       << vp.GetSectionPlane ();
	G4cout << G4endl;
      }
      return;
    }

    G4double F = 1.;
    switch (iSelector) {
    default:
    case 0:
      vp.UnsetSectionPlane();
      break;
    case 1:
      F = G4UIcommand::ValueOf(unit);
      x *= F; y *= F; z *= F;
      vp.SetSectionPlane(G4Plane3D(G4Normal3D(nx,ny,nz), G4Point3D(x,y,z)));
      vp.SetViewpointDirection(G4Normal3D(nx,ny,nz));
      break;
    }

    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Section drawing is now: ";
      if (vp.IsSection ()) G4cout << "on";
      else                    G4cout << "off";
      G4cout << ".\nSection plane is now: "
	     << vp.GetSectionPlane ();
      G4cout << G4endl;
    }
  }

  else if (command == fpCommandStyle) {
    G4ViewParameters::DrawingStyle existingStyle = vp.GetDrawingStyle();
    const size_t iPos0 = 0;
    if (newValue[iPos0] == 'w') {  // "wireframe"
      switch (existingStyle) {
      case G4ViewParameters::wireframe:
	break;
      case G4ViewParameters::hlr:
	break;
      case G4ViewParameters::hsr:
	vp.SetDrawingStyle(G4ViewParameters::wireframe);
        break;
      case G4ViewParameters::hlhsr:
	vp.SetDrawingStyle(G4ViewParameters::hlr);
        break;
      }
    }
    else if (newValue[iPos0] == 's') {  // "surface"
      switch (existingStyle) {
      case G4ViewParameters::wireframe:
	vp.SetDrawingStyle(G4ViewParameters::hsr);
	break;
      case G4ViewParameters::hlr:
	vp.SetDrawingStyle(G4ViewParameters::hlhsr);
	break;
      case G4ViewParameters::hsr:
	break;
      case G4ViewParameters::hlhsr:
	break;
      }
    }
    else {
      if (verbosity >= G4VisManager::errors) {
	G4cout << "ERROR: \"" << newValue << "\" not recognised."
	  "  Looking for 'w' or 's' first character." << G4endl;
      }
      return;
    }
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Drawing style of viewer \"" << currentViewer->GetName()
	     << "\" set to " << vp.GetDrawingStyle()
	     << G4endl;
    }
  }

  else if (command == fpCommandUpThetaPhi) {
    G4double theta, phi;
    ConvertToDoublePair(newValue, theta, phi);
    G4double x = std::sin (theta) * std::cos (phi);
    G4double y = std::sin (theta) * std::sin (phi);
    G4double z = std::cos (theta);
    fUpVector = G4ThreeVector (x, y, z);
    vp.SetUpVector(fUpVector);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Up direction set to " << vp.GetUpVector() << G4endl;
    }
  }

  else if (command == fpCommandUpVector) {
    fUpVector = G4UIcommand::ConvertTo3Vector(newValue).unit();
    vp.SetUpVector(fUpVector);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Up direction set to " << vp.GetUpVector() << G4endl;
    }
  }

  else if (command == fpCommandViewpointThetaPhi) {
    G4double theta, phi;
    ConvertToDoublePair(newValue, theta, phi);
    G4double x = std::sin (theta) * std::cos (phi);
    G4double y = std::sin (theta) * std::sin (phi);
    G4double z = std::cos (theta);
    fViewpointVector = G4ThreeVector (x, y, z);
    vp.SetViewAndLights(fViewpointVector);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Viewpoint direction set to "
	     << vp.GetViewpointDirection() << G4endl;
      if (vp.GetLightsMoveWithCamera ()) {
	G4cout << "Lightpoint direction set to "
	       << vp.GetActualLightpointDirection () << G4endl;
      }
    }
  }

  else if (command == fpCommandViewpointVector) {
    fViewpointVector = G4UIcommand::ConvertTo3Vector(newValue).unit();
    vp.SetViewAndLights(fViewpointVector);
    if (verbosity >= G4VisManager::confirmations) {
      G4cout << "Viewpoint direction set to "
	     << vp.GetViewpointDirection() << G4endl;
      if (vp.GetLightsMoveWithCamera ()) {
	G4cout << "Lightpoint direction set to "
	       << vp.GetActualLightpointDirection () << G4endl;
      }
    }
  }

  else {
    if (verbosity >= G4VisManager::errors) {
      G4cout <<
	"ERROR: G4VisCommandsViewerSet::SetNewValue: unrecognised command."
	     << G4endl;
    }
    return;
  }

  SetViewParameters(currentViewer,vp);
}
