diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index dccec3c36f92076c4ebc1717abf50dbdf262e6d9..7bfec2f839e37b159db2be520ab9dd89349d9536 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -1291,6 +1291,8 @@ StringXNumber ViewOptions_Number[] = {
     "Number of intervals" },
   { F,   "NbTimeStep" , opt_view_nb_timestep , 1. ,
     "Number of time steps in the view (do not change this!)" },
+  { F,   "NormalRaise" , opt_view_normal_raise , 0. , 
+    "Elevation of the view along the normal (in model coordinates)" },
   { F|O, "Normals" , opt_view_normals , 0. ,
     "Display size of normal vectors (in pixels)" }, 
 
diff --git a/Common/Options.cpp b/Common/Options.cpp
index e14f73524a535580aa5ddaa467a1fa22ec6044b3..ef5a7be785e59212871da7887fd2af9cd1e0ac4d 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -1,4 +1,4 @@
-// $Id: Options.cpp,v 1.370 2007-11-28 17:02:19 geuzaine Exp $
+// $Id: Options.cpp,v 1.371 2007-12-07 20:49:05 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -5603,6 +5603,20 @@ double opt_view_raise2(OPT_ARGS_NUM)
   return opt->Raise[2];
 }
 
+double opt_view_normal_raise(OPT_ARGS_NUM)
+{
+  GET_VIEW(0.);
+  if(action & GMSH_SET) {
+    opt->NormalRaise = val;
+    if(view) view->setChanged(true);
+  }
+#if defined(HAVE_FLTK)
+  if(_gui_action_valid(action, num))
+    WID->view_value[46]->value(opt->NormalRaise);
+#endif
+  return opt->NormalRaise;
+}
+
 double opt_view_transform00(OPT_ARGS_NUM)
 {
   GET_VIEW(0.);
diff --git a/Common/Options.h b/Common/Options.h
index aac39194c44390dd5da32873b50d6673d071d6ee..91d48d4bca20b53f2915f142b04466d24ac6e8b7 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -553,6 +553,7 @@ double opt_view_offset2(OPT_ARGS_NUM);
 double opt_view_raise0(OPT_ARGS_NUM);
 double opt_view_raise1(OPT_ARGS_NUM);
 double opt_view_raise2(OPT_ARGS_NUM);
+double opt_view_normal_raise(OPT_ARGS_NUM);
 double opt_view_transform00(OPT_ARGS_NUM);
 double opt_view_transform01(OPT_ARGS_NUM);
 double opt_view_transform02(OPT_ARGS_NUM);
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index 3e64e74a13669e33b2aced5c13510ea49fdd0bda..4a24da65d99e1b3a076d8eb993876bd402fb334c 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.553 2007-11-28 14:18:09 remacle Exp $
+// $Id: Callbacks.cpp,v 1.554 2007-12-07 20:49:05 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -1338,6 +1338,7 @@ void view_options_ok_cb(CALLBACK_ARGS)
   double raise0 = opt_view_raise0(current, GMSH_GET, 0);
   double raise1 = opt_view_raise1(current, GMSH_GET, 0);
   double raise2 = opt_view_raise2(current, GMSH_GET, 0);
+  double normal_raise = opt_view_normal_raise(current, GMSH_GET, 0);
   double timestep = opt_view_timestep(current, GMSH_GET, 0);
   double arrow_size = opt_view_arrow_size(current, GMSH_GET, 0);
   double arrow_size_proportional = opt_view_arrow_size_proportional(current, GMSH_GET, 0);
@@ -1642,6 +1643,10 @@ void view_options_ok_cb(CALLBACK_ARGS)
       if(force || (val != raise2))
         opt_view_raise2(i, GMSH_SET, val);
 
+      val = WID->view_value[46]->value();
+      if(force || (val != normal_raise))
+        opt_view_normal_raise(i, GMSH_SET, val);
+
       val = WID->view_value[50]->value();
       if(force || (val != timestep))
         opt_view_timestep(i, GMSH_SET, val);
diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index c4282222c55353b9666165afcb41fdd17c71198e..38e471cb3c05a0cde15955e9b5b42fa1bb60ed64 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI.cpp,v 1.645 2007-11-28 14:18:10 remacle Exp $
+// $Id: GUI.cpp,v 1.646 2007-12-07 20:49:05 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -3197,7 +3197,9 @@ void GUI::create_option_window()
       view_value[44] = new Fl_Value_Input(L + 2 * WB + 2 * IW-WB, 2 * WB + 3 * BH, 7*IW/10, BH, "Y");
       view_value[45] = new Fl_Value_Input(L + 2 * WB + 2 * IW-WB, 2 * WB + 4 * BH, 7*IW/10, BH, "Z");
 
-      for(int i = 40; i <= 45; i++){
+      view_value[46] = new Fl_Value_Input(L + 2 * WB, 2 * WB + 5 * BH, 3*ss, BH, "Normal raise");
+
+      for(int i = 40; i <= 46; i++){
 	view_value[i]->align(FL_ALIGN_RIGHT);
 	view_value[i]->when(FL_WHEN_RELEASE);
 	view_value[i]->callback(view_options_ok_cb);
@@ -3211,29 +3213,29 @@ void GUI::create_option_window()
 	view_value[i]->callback(view_options_ok_cb);
       }
 
-      view_butt[6] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 5 * BH, BW, BH, "Use general transformation expressions");
+      view_butt[6] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 6 * BH, BW, BH, "Use general transformation expressions");
       view_butt[6]->type(FL_TOGGLE_BUTTON);
       view_butt[6]->callback(view_options_ok_cb, (void*)"general_transform");
 
-      view_choice[11] = new Fl_Choice(L + 2 * WB, 2 * WB + 6 * BH, IW, BH, "Data source");
+      view_choice[11] = new Fl_Choice(L + 2 * WB, 2 * WB + 7 * BH, IW, BH, "Data source");
       view_choice[11]->align(FL_ALIGN_RIGHT);
       view_choice[11]->add("Self");
       view_choice[11]->callback(view_options_ok_cb);
 
-      view_value[2] = new Fl_Value_Input(L + 2 * WB, 2 * WB + 7 * BH, IW, BH, "Factor");
+      view_value[2] = new Fl_Value_Input(L + 2 * WB, 2 * WB + 8 * BH, IW, BH, "Factor");
       view_value[2]->align(FL_ALIGN_RIGHT);
       view_value[2]->when(FL_WHEN_RELEASE);
       view_value[2]->callback(view_options_ok_cb);
 
-      view_input[4] = new Fl_Input(L + 2 * WB, 2 * WB + 8 * BH, IW, BH, "X expression");
+      view_input[4] = new Fl_Input(L + 2 * WB, 2 * WB + 9 * BH, IW, BH, "X expression");
       view_input[4]->align(FL_ALIGN_RIGHT);
       view_input[4]->callback(view_options_ok_cb);
 
-      view_input[5] = new Fl_Input(L + 2 * WB, 2 * WB + 9 * BH, IW, BH, "Y expression");
+      view_input[5] = new Fl_Input(L + 2 * WB, 2 * WB + 10 * BH, IW, BH, "Y expression");
       view_input[5]->align(FL_ALIGN_RIGHT);
       view_input[5]->callback(view_options_ok_cb);
 
-      view_input[6] = new Fl_Input(L + 2 * WB, 2 * WB + 10 * BH, IW, BH, "Z expression");
+      view_input[6] = new Fl_Input(L + 2 * WB, 2 * WB + 11 * BH, IW, BH, "Z expression");
       view_input[6]->align(FL_ALIGN_RIGHT);
       view_input[6]->callback(view_options_ok_cb);
 
@@ -3548,7 +3550,8 @@ void GUI::update_view_window(int num)
   opt_view_raise0(num, GMSH_GUI, 0);
   opt_view_raise1(num, GMSH_GUI, 0);
   opt_view_raise2(num, GMSH_GUI, 0);
-  for(int i = 43; i <= 45; i++) {
+  opt_view_normal_raise(num, GMSH_GUI, 0);
+  for(int i = 43; i <= 46; i++) {
     view_value[i]->step(val2/100.);
     view_value[i]->minimum(-val2);
     view_value[i]->maximum(val2);
diff --git a/Graphics/Post.cpp b/Graphics/Post.cpp
index 6813feb11b71a947d3e5a33a63c1706aff39bda1..da61841c8565e4a3243b4d3df642e83b399491d0 100644
--- a/Graphics/Post.cpp
+++ b/Graphics/Post.cpp
@@ -1,4 +1,4 @@
-// $Id: Post.cpp,v 1.141 2007-11-08 14:44:13 geuzaine Exp $
+// $Id: Post.cpp,v 1.142 2007-12-07 20:49:05 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -75,6 +75,31 @@ SVector3 getPointNormal(PView *p, double v)
   return n;
 }
 
+SVector3 getLineNormal(PView *p, double x[2], double y[2], double z[2])
+{
+  SBoundingBox3d bb = p->getData()->getBoundingBox();
+  if(bb.min().z() == bb.max().z())
+    return SVector3(0., 0., 1.);
+  else if(bb.min().y() == bb.max().y())
+    return SVector3(0., 1., 0.);
+  else if(bb.min().x() == bb.max().x())
+    return SVector3(1., 0., 0.);
+  else{
+    // we don't have any info about the normal, just pick one
+    SVector3 t(x[1] - x[0], y[1] - y[0], z[1] - z[0]);
+    SVector3 ex(0., 0., 0.);
+    if(t[0] == 0.)
+      ex[0] = 1.;
+    else if(t[1] == 0.)
+      ex[1] = 1.;
+    else
+      ex[2] = 1.;
+    SVector3 n = crossprod(t, ex);
+    n.normalize();
+    return n;
+  }
+}
+
 void getLineNormal(PView *p, double x[2], double y[2], double z[2],
 		   double *v, SVector3 n[2], bool computeNormal)
 {
@@ -102,20 +127,8 @@ void getLineNormal(PView *p, double x[2], double y[2], double z[2],
       n[0] = n[1] = SVector3(0., 1., 0.);
     else if(bb.min().x() == bb.max().x())
       n[0] = n[1] = SVector3(1., 0., 0.);
-    else{
-      // we don't have any info about the normal, just pick one
-      SVector3 t(x[1] - x[0], y[1] - y[0], z[1] - z[0]);
-      SVector3 ex(0., 0., 0.);
-      if(t[0] == 0.)
-	ex[0] = 1.;
-      else if(t[1] == 0.)
-	ex[1] = 1.;
-      else
-	ex[2] = 1.;
-      n[0] = crossprod(t, ex);
-      n[0].normalize();
-      n[1] = n[0];
-    }
+    else
+      n[0] = n[1] = getLineNormal(p, x, y, z);
   }
 }
 
@@ -190,8 +203,8 @@ void applyGeneralRaise(PView *p, int numNodes, int numComp,
   }
 }
 
-void changeCoordinates(PView *p, int iele, int numNodes, int numComp, 
-		       double xyz[NMAX][3], double val[NMAX][9])
+void changeCoordinates(PView *p, int iele, int numNodes, int numEdges, 
+		       int numComp, double xyz[NMAX][3], double val[NMAX][9])
 {
   PViewOptions *opt = p->getOptions();
 
@@ -236,6 +249,27 @@ void changeCoordinates(PView *p, int iele, int numNodes, int numComp,
     }
   }
 
+  if(opt->NormalRaise && numEdges >= 1 && numEdges <= 4){
+    SVector3 n;
+    if(numEdges == 1){
+      // assumes lines in z=0 plane, and raises in that plane
+      double x[2] = {xyz[0][0], xyz[1][0]};
+      double y[2] = {xyz[0][1], xyz[1][1]};
+      double z[2] = {xyz[0][2], xyz[1][2]};
+      SVector3 p(0, 0, 1.);
+      SVector3 t(x[1] - x[0], y[1] - y[0], z[1] - z[0]);
+      n = crossprod(t, p);
+      n.normalize();
+    }
+    else
+      n = normal3(xyz);
+    for(int i = 0; i < numNodes; i++){
+      double v = ComputeScalarRep(numComp, val[i]);
+      for(int j = 0; j < 3; j++)
+	xyz[i][j] += n[j] * opt->NormalRaise * v;
+    }
+  }
+
   if(numComp == 3 && opt->VectorType == PViewOptions::Displacement){
     for(int i = 0; i < numNodes; i++){
       for(int j = 0; j < 3; j++)
@@ -894,7 +928,7 @@ void addElementsInArrays(PView *p, bool preprocessNormalsOnly)
       for(int k = 0; k < numComp; k++)
 	data->getValue(i, j, k, opt->TimeStep, val[j][k]);
     }
-    changeCoordinates(p, i, numNodes, numComp, xyz, val);
+    changeCoordinates(p, i, numNodes, numEdges, numComp, xyz, val);
 
     for(int j = 0; j < numNodes; j++)
       opt->TmpBBox += SPoint3(xyz[j][0], xyz[j][1], xyz[j][2]);
@@ -1131,7 +1165,7 @@ void drawGlyphs(PView *p)
       for(int k = 0; k < numComp; k++)
 	data->getValue(i, j, k, opt->TimeStep, val[j][k]);
     }
-    changeCoordinates(p, i, numNodes, numComp, xyz, val);
+    changeCoordinates(p, i, numNodes, numEdges, numComp, xyz, val);
     if(opt->IntervalsType == PViewOptions::Numeric)
       drawNumberGlyphs(p, numNodes, numComp, xyz, val);
     if(dim == 2 && opt->Normals)
diff --git a/Post/PViewOptions.h b/Post/PViewOptions.h
index 1ff7ae59c655866b5109f6dccbc3cf3234da60ba..e7b9d948c445b32de2ceac4da35c26d233830cfc 100644
--- a/Post/PViewOptions.h
+++ b/Post/PViewOptions.h
@@ -70,7 +70,8 @@ class PViewOptions {
   double AxesPosition[6];
   double CustomMin, CustomMax, TmpMin, TmpMax, ExternalMin, ExternalMax;
   SBoundingBox3d TmpBBox;
-  double Offset[3], Raise[3], Transform[3][3], DisplacementFactor, Explode;
+  double Offset[3], Raise[3], Transform[3][3], DisplacementFactor, NormalRaise;
+  double Explode;
   double ArrowSize, ArrowRelHeadRadius, ArrowRelStemRadius, ArrowRelStemLength;
   double Normals, Tangents;
   int Visible, IntervalsType, NbIso, ArrowSizeProportional;