/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkTextActor.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkTextActor.h" #include "vtkObjectFactory.h" #include "vtkTextMapper.h" #include "vtkTextProperty.h" #include "vtkViewport.h" #include "vtkWindow.h" vtkCxxRevisionMacro(vtkTextActor, "$Revision: 1.22 $"); vtkStandardNewMacro(vtkTextActor); vtkCxxSetObjectMacro(vtkTextActor,TextProperty,vtkTextProperty); // ---------------------------------------------------------------------------- vtkTextActor::vtkTextActor() { // To remain compatible with code using vtkActor2D, we must set // position coord to Viewport, not Normalized Viewport // so...compute equivalent coords for initial position this->PositionCoordinate->SetCoordinateSystemToViewport(); this->AdjustedPositionCoordinate = vtkCoordinate::New(); this->AdjustedPositionCoordinate->SetCoordinateSystemToNormalizedViewport(); // Create default text mapper vtkTextMapper *mapper = vtkTextMapper::New(); this->SetMapper(mapper); mapper->Delete(); this->TextProperty = vtkTextProperty::New(); this->LastOrigin[0] = 0; this->LastOrigin[1] = 0; this->LastSize[0] = 0; this->LastSize[1] = 0; this->MinimumSize[0] = 10; this->MinimumSize[1] = 10; this->MaximumLineHeight = 1.0; this->ScaledText = 0; this->AlignmentPoint = 0; this->FontScaleExponent = 1; this->FontScaleTarget = 10; // IMPORTANT: backward compat: the buildtime is updated here so that the // TextProperty->GetMTime() is lower than BuildTime. In that case, this // will prevent the TextProperty to override the mapper's TextProperty // when the actor is created after the mapper. this->BuildTime.Modified(); } // ---------------------------------------------------------------------------- vtkTextActor::~vtkTextActor() { this->AdjustedPositionCoordinate->Delete(); this->SetTextProperty(NULL); } // ---------------------------------------------------------------------------- void vtkTextActor::SetNonLinearFontScale(double exp, int tgt) { if (this->FontScaleExponent == exp && this->FontScaleTarget == tgt) { return; } this->FontScaleExponent = exp; this->FontScaleTarget = tgt; this->Modified(); } // ---------------------------------------------------------------------------- void vtkTextActor::SetMapper(vtkTextMapper *mapper) { this->vtkActor2D::SetMapper( mapper ); } // ---------------------------------------------------------------------------- void vtkTextActor::SetMapper(vtkMapper2D *mapper) { if (mapper->IsA("vtkTextMapper")) { this->SetMapper( (vtkTextMapper *)mapper ); } else { vtkErrorMacro("Must use vtkTextMapper for this class"); } } // ---------------------------------------------------------------------------- void vtkTextActor::SetInput(const char* input) { vtkTextMapper *mapper = (vtkTextMapper *)this->GetMapper(); if (!mapper) { vtkErrorMacro("Actor has not vtkTextMapper"); } mapper->SetInput(input); } // ---------------------------------------------------------------------------- char* vtkTextActor::GetInput() { vtkTextMapper *mapper = (vtkTextMapper *)this->GetMapper(); if (!mapper) { vtkErrorMacro("Actor has not vtkTextMapper"); } return mapper->GetInput(); } // ---------------------------------------------------------------------------- void vtkTextActor::ShallowCopy(vtkProp *prop) { vtkTextActor *a = vtkTextActor::SafeDownCast(prop); if ( a != NULL ) { this->SetPosition2(a->GetPosition2()); this->SetMinimumSize(a->GetMinimumSize()); this->SetMaximumLineHeight(a->GetMaximumLineHeight()); this->SetScaledText(a->GetScaledText()); this->SetAlignmentPoint(a->GetAlignmentPoint()); this->SetTextProperty(a->GetTextProperty()); } // Now do superclass (mapper is handled by it as well). this->vtkActor2D::ShallowCopy(prop); } // ---------------------------------------------------------------------------- // Release any graphics resources that are being consumed by this actor. // The parameter window could be used to determine which graphic // resources to release. void vtkTextActor::ReleaseGraphicsResources(vtkWindow *win) { this->vtkActor2D::ReleaseGraphicsResources(win); } // ---------------------------------------------------------------------------- int vtkTextActor::RenderOverlay(vtkViewport *viewport) { // Everything is built in RenderOpaqueGeometry, just have to render return this->vtkActor2D::RenderOverlay(viewport); } // ---------------------------------------------------------------------------- int vtkTextActor::RenderOpaqueGeometry(vtkViewport *viewport) { int size[2]; vtkTextMapper *mapper = (vtkTextMapper *)this->GetMapper(); if (!mapper) { vtkErrorMacro(<<"Need mapper to render text actor"); return 0; } vtkTextProperty *tprop = this->GetTextProperty(); vtkTextProperty *tpropmapper = mapper->GetTextProperty(); if (!tprop && !tpropmapper) { vtkErrorMacro(<<"Need text property to render text actor"); return 0; } if (tprop && tprop->GetMTime() > this->BuildTime) { // Shallow copy here so that the size of the text prop is not affected // by the automatic adjustment of its text mapper's size (i.e. its // mapper's text property is identical except for the font size // which will be modified later). This allows text actors to // share the same text property. if (tpropmapper && tprop->GetMTime() > tpropmapper->GetMTime()) { tpropmapper->ShallowCopy(tprop); } } int *point1, *point2; double u, v; // we don't need to do anything additional, just pass the call // right through to the actor if (!this->ScaledText) { point1 = this->PositionCoordinate->GetComputedViewportValue(viewport); point2 = this->Position2Coordinate->GetComputedViewportValue(viewport); size[0] = point2[0] - point1[0]; size[1] = point2[1] - point1[1]; switch (this->AlignmentPoint) { case 0: u = point1[0]; v = point1[1]; break; case 1: u = point1[0] + size[0]/2; v = point1[1]; break; case 2: u = point2[0]; v = point1[1]; break; case 3: u = point1[0]; v = point1[1] + size[1]/2; break; case 4: u = point1[0] + size[0]/2; v = point1[1] + size[1]/2; break; case 5: u = point2[0]; v = point1[1] + size[1]/2; break; case 6: u = point1[0]; v = point2[1]; break; case 7: u = point1[0] + size[0]/2; v = point2[1]; break; case 8: u = point2[0]; v = point2[1]; break; } viewport->ViewportToNormalizedViewport(u, v); this->AdjustedPositionCoordinate->SetValue(u,v); this->BuildTime.Modified(); } else { point1 = this->PositionCoordinate->GetComputedViewportValue(viewport); point2 = this->Position2Coordinate->GetComputedViewportValue(viewport); size[0] = point2[0] - point1[0]; size[1] = point2[1] - point1[1]; // Check to see whether we have to rebuild everything int positionsHaveChanged = 0; if (viewport->GetMTime() > this->BuildTime || (viewport->GetVTKWindow() && viewport->GetVTKWindow()->GetMTime() > this->BuildTime)) { // if the viewport has changed we may - or may not need // to rebuild, it depends on if the projected coords change if (this->LastSize[0] != size[0] || this->LastSize[1] != size[1] || this->LastOrigin[0] != point1[0] || this->LastOrigin[1] != point1[1]) { positionsHaveChanged = 1; } } // Check to see whether we have to rebuild everything if (positionsHaveChanged || this->GetMTime() > this->BuildTime || mapper->GetMTime() > this->BuildTime || tpropmapper->GetMTime() > this->BuildTime) { vtkDebugMacro(<<"Rebuilding text"); this->LastOrigin[0] = point1[0]; this->LastOrigin[1] = point1[1]; // Lets try to minimize the number of times we change the font size. // If the width of the font box has not changed by more than a pixel // (numerical issues) do not recompute font size. if (mapper->GetMTime() > this->BuildTime || tpropmapper->GetMTime() > this->BuildTime || this->LastSize[0] < size[0] - 1 || this->LastSize[1] < size[1] - 1 || this->LastSize[0] > size[0] + 1 || this->LastSize[1] > size[1] + 1) { this->LastSize[0] = size[0]; this->LastSize[1] = size[1]; // limit by minimum size if (this->MinimumSize[0] > size[0]) { size[0] = this->MinimumSize[0]; } if (this->MinimumSize[1] > size[1]) { size[1] = this->MinimumSize[1]; } int max_height = (int)(this->MaximumLineHeight * (float)size[1]); int fsize = mapper->SetConstrainedFontSize( viewport, size[0], (size[1] < max_height ? size[1] : max_height)); // apply non-linear scaling fsize = static_cast(pow(static_cast(fsize),this->FontScaleExponent)* pow(this->FontScaleTarget, 1.0 - this->FontScaleExponent)); tpropmapper->SetFontSize(fsize); } // now set the position of the Text int fpos[2]; switch (tpropmapper->GetJustification()) { case VTK_TEXT_LEFT: fpos[0] = point1[0]; break; case VTK_TEXT_CENTERED: fpos[0] = point1[0] + size[0]/2; break; case VTK_TEXT_RIGHT: fpos[0] = point1[0]+size[0]; break; } switch (tpropmapper->GetVerticalJustification()) { case VTK_TEXT_TOP: fpos[1] = point1[1] + size[1]; break; case VTK_TEXT_CENTERED: fpos[1] = point1[1] + size[1]/2; break; case VTK_TEXT_BOTTOM: fpos[1] = point1[1]; break; } u = fpos[0]; v = fpos[1]; viewport->ViewportToNormalizedViewport(u, v); this->AdjustedPositionCoordinate->SetValue(u,v); this->BuildTime.Modified(); } } // Everything is built, just have to render return this->vtkActor2D::RenderOpaqueGeometry(viewport); } // ---------------------------------------------------------------------------- void vtkTextActor::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); if (this->TextProperty) { os << indent << "Text Property:\n"; this->TextProperty->PrintSelf(os,indent.GetNextIndent()); } else { os << indent << "Text Property: (none)\n"; } os << indent << "MaximumLineHeight: " << this->MaximumLineHeight << endl; os << indent << "MinimumSize: " << this->MinimumSize[0] << " " << this->MinimumSize[1] << endl; os << indent << "ScaledText: " << this->ScaledText << endl; os << indent << "AlignmentPoint: " << this->AlignmentPoint << endl; os << indent << "FontScaleExponent: " << this->FontScaleExponent << endl; os << indent << "FontScaleTarget: " << this->FontScaleTarget << endl; }