WP Syntax-Highlighting with Code in an (external) Text-File
Pretty much the first thing one does when posting code on a Wordpres-Blog, is to look for a suitable Syntax-Highlighting Plugin. So did I. SyntaxHighlighter Evolved is the one I stuck with, but I guess that’s up to you (This method should work with all of them but how would I know?). The second Plugin you need would be something to make PHP code work in your posts and pages (I use Exec-PHP).
So now, instead of writing your code directly into your posts/pages, you can make a .txt file which is simply linked into your post/page. That way you can edit code and posts separately so
- you (or other users) can’t accidentally mess up your code when editing the post
- shorter posts -> no matter how long the code snippet, you just need one line in your post
- you can supply a direct download link to the text file holding the code
A good Text Editor
To prevent messed up code when using non-english characters, save the .txt-File (or whatever format you choose to save your code file) as UTF-8. One of the most popular text editors, that is able to convert text to UTF-8 is Notepad++.
Open the text file, go to Encoding -> Convert to UTF-8
You can check the encoding of the file in the lower right corner of the window.
PHP Code Sample
Let’s assume our code snippet is PHP and reads as follows.
[php]<?php echo "Hello World"; ?>[/php]
Instead of putting this line into your post or page, you put it into a new text file. Save the file as PHP-sample.txt and upload it to your blog (either via the Media Library or FTP, as you wish). Write down the address of the file. I uploaded my code file into the WordPress Media Library, so the address is http://nj.riotdowntown.com/wp-content/uploads/2011/08/PHP-sample.txt.
If you look at my file you will notice, that it looks a bit weird. Due to the fact that I use Exec-PHP, I can’t have <?php in my code snippet, because the PHP-Plugin would think that I want to execute that code rather than display it. I simply replaced the characters < with < and > with > to work around this problem (HTML Sonderzeichen). The characters will by rendered correctly but the PHP doesn’t interfere with the plugin. You do not have to worry about this problem if you don’t have <?php in your code snippet (no matter which programming language you use to show your code in).
The last thing to do is to get the code from your uploaded file to your blog-post. So in your post you put something like
<?php include('http://nj.riotdowntown.com/wp-content/uploads/2011/08/PHP-sample.txt'); ?>
with the correct path to your PHP-sample.txt. The result will look like this:
<?php echo "Hello World"; ?>
Notice that the SyntaxHighlighter Evolved tags like [php], [/php] [vb], etc. (Bundled Brushes) are now located in the external text file! So all the parameters go in there, too.
A little bit deeper
We can make things a bit easier if we have a post with multipe separate code snippets. Since we have the ability to use (the full force of) PHP, we can just define a variable to the path with our snippets. In my case that would be http://nj.riotdowntown.com/wp-content/uploads/2011/08/. So at the top of the post we add (the definition of variables is always at the top, before they are used!)
<?php $curPath = 'http://nj.riotdowntown.com/wp-content/uploads/2011/08/' ?>
so we will be able to use $curPath instead of that long address every time.
So the line
<?php include('http://nj.riotdowntown.com/wp-content/uploads/2011/08/PHP-sample.txt'); ?>
becomes
<?php include($curPath . 'PHP-sample.txt'); ?>
Too much
In case you change your URL or you put your WP-installation into a subfolder, WordPress should update all links accordingly, I think. But if you’re the worried one you can use get_bloginfo(‘url’) as a dynamic link to your own page, see. Function Reference/get bloginfo.
So we will change the definition of $curPath at the top of our posts according to this
<?php $curPath = get_bloginfo('url') . '/wp-content/uploads/2011/08/' ?>
The following picture shows my backend editor with the “source code” of the post Obtain the structure for a CATProduct
As you see, you can still have normal SyntaxHighlighter syntax mixed in into your post. business as usual..
..and a little more
Let’s say you want to show your readers the (syntax-highlighted) contents of a .php file on your server. Firstly you need another .php that retrieves the contents and formats it so that you can use it in your post or page. Here the name shall be YF-Box_SOURCE.php and it looks like this:
<?php
$string = file_get_contents('../../wp-content/themes/matala/YF-Box.php');
echo '[php collapse="true"]' . htmlspecialchars($string) . '[/php]';
?>
The following line goes into your post:
<?php include get_bloginfo('url') . '/CODE-Files/YF-Box/YF-Box_SOURCE.php'; ?>
Notes:
the .php file you want to show the contents of, must be located on the same webspace.
Requirements:
Links/special Thanks:
- Viper007Bond
- automattic
- McShelby
- Function Reference/get bloginfo
- HTML Sonderzeichen – Liste Ersatzzeichen, Sonderzeichen Darstellung in HTML
Custom CSS for WP-Plugins
Many plugins offer the possibility to use custom style sheets for the display of their output. So the user can control how the plugin looks rather than its programmer. I want to use the plugin RSS in Page as an example. The shortcode you put in your posts or page normally looks something like this:
[rssinpage rssfeed='feedURL']
for which we have the following optional attributes (see RSS in Page for full list):
- rssformat allows you to format the output using format parameters e.g. the default x: Y – w
z where x is the date, Y is the title with a link, y is the title, z is the description and w is the feed title - rssitems=’number’ sets the number of items to return, default is 5
- rssorder=’asc’ returns items from oldest to newest, default is ‘desc’ which returns items from newest to oldest
- rsstarget=’_blank’ opens item link in new window, default is ‘_self’
- rssdateformat allows item date to be formatted using php date parameters, default is RFC 2822 formatted date
- rss description=’no’ suppresses default display of the description
- rsscss=’yourclassname’ allows you to give the list a specific style rather than inheriting the default content list style in your theme
- …
rsscss='yourclassname' is the parameter we want. So our shortcode would look something like:
[rssinpage rssfeed='feedURL' rsscss='yourclassname']
Where yourclassname can be any name you like. This will (obviously..) be the name of our CSS class.
You can edit the style sheet (CSS) for your currently applied theme in your WP back-end. After you log in, go to -> Appearance -> Editor. Here you can make changes to to your themes style.css direktly, but the actual file on the server has to be writeable in order for WP to save your changes.
If your style.css is not writeable you will see this (notice the message on the bottom)
To make your style.css writeable you have to have access to your webspace (where your wordpress files are hosted, see Changing File Permissions). In this example I use the FileZilla Client to set the permissions via FTP.
Locate the file style.css in ./wp-content/themes/##Your_Active_Theme##. Right-click it and select Permissions.
Set the permissions to 666 meaning read and write access for everyone (owner, group, others). Hit OK and you’re almost done. It might not be a bad idea to make a backup copy of the file (everytime) before you change it, at least while your connected anyway.
Now you can go back to your WP back-end and edit the stylesheet file from there (WP Back-End -> Appearance -> Editor).
Now we will add two classes at the top of the style.css file. The first class is called rssclass_headline and the second one rssclass.
/* titus addition RSS in Page */
.rssclass_headline{font-size: 19px; margin-bottom: 0; margin-top: -20px;}
ul.rssclass_headline{list-style: none;}
ul.rssclass_headline li {color: #666666;}
ul.rssclass_headline a {/* color: #ff0000; */ text-decoration: none; font-weight: bold; text-transform: uppercase;}
/* ul.rssclass_headline a:hover {color: #66cc33; text-decoration: none; } */
ul.rssclass{list-style: square;}
ul.rssclass li {color: #666666; margin-bottom:20px;}
ul.rssclass a {text-decoration: none; font-weight: bold; text-transform: uppercase;}
/* ul.rssclass a:hover {color: #66cc33; text-decoration: none;} */
/* titus addition */
The class rssclass_headline is just to format the blog title (of the blog the feed comes from). For example the headline font-size is bigger, the text is transformed to uppercase and list-style: none; removes the bullet for the (list) item. The parameter rssitems='1' causes the feed to display only one feed item (we just want to display the title once..). Also add rssformat='w', so instead of the post title, the blog title will be displayed.
So the code for your headline could look like
[rssinpage rssfeed='feedURL' rssitems='1' rssformat='w' rsscss='rssclass_headline']
To link the title to the blog just wrap it
<a href="blogURL">[rssinpage rssfeed='feedURL' rssitems='1' rssformat='w' rsscss='rssclass_headline']</a>
The other CSS class rssclass handles the formatting of the feed items themselves. I.e. list-style: square; will change the standard list bullet to a square. So the second line of code (first line was just for the headline) will generate the feed items and should look something like
[rssinpage rssfeed='feedURL' rsscss='rssclass']
You may want to add some additional parameters from the list to make it look as you want it to.
I will leave you with some code I used for the page CATArchive
<!-- Headline -->
<a href="http://nj.riotdowntown.com/category/catia/">[rssinpage rssfeed='http://nj.riotdowntown.com/feed/' rssitems='1' rssformat='w' rsscss='rssclass_headline']</a><!-- Feed Items -->
[rssinpage rssfeed='http://nj.riotdowntown.com/category/catia/feed/' rssitems='15' rssdescriptionlength='350' rssdateformat='j F Y H:i:s' rsstimezone='Europe/Berlin' rsscss='rssclass']
Requirements:
Links/special Thanks:
Obtain the structure for a CATProduct
A Product structure in CATIA can be inconveniently complex. A programmer often needs the knowledge of Product and Part relations which are not necessarily provided by CATIA’s infrastructure. Thus this example shows how to obtain the structure of a Product by utilizing recursive methods.
Core Functions
Class – C_DocStructureObject
Create a new class in your VBA-Project, call it C_DocStructureObject and copy & paste the following code
Public Product As Product Public Name As String Public PartNumber As String Public DocType As String Public Reference As Reference Public RefPath As String Public SubProductsCount As Integer Public SubProductsN As String 'N = Name Public SubProductsPN As String 'PN = PartNumber Public layer As Integer Public FileName As String Public FilePath As String Public IsComponent As Boolean '' see EXAMPLE 'Public NomCla As String
Module – M_DocStructure
Now you create a new module called M_DocStructure and paste these lines (click on show source)
' ====================================================================
' == PUBLIC VARIABLES ==
' == may be used throughout the code (after M_DocStructure call) ==
' == können im Code (nach Aufruf von M_DocStructure call) beliebig ==
' == benutzt werden. ==
' ====================================================================
Public MainProductDoc As ProductDocument ' root Product ==
Public pProducts As Collection ' pProducts ==
Public fProduct As C_DocStructureObject ' ==
Public pDocuments As Collection ' pDocuments ==
Public fDocument As Document ' ==
' ====================================================================
'----------------------------
' MsgBox-Text
'=========================================================
Private Const MsgStr_NoDocs_EN = "No documents found. Macro will now end."
Private Const MsgStr_NoDocs_DE = "Keine Dokumente gefunden. Makro wird beendet."
'----------------------------
' CreateDocStructureObject:
' - creates a classobject and fills it with infos _
' about the current product
' - erstellt ein Objekt der Klasse und füllt es mit _
' Infos zum aktuellen Product
'=========================================================
Public Sub CreateDocStructureObject(iProduct As Product)
Dim i As Integer
' create a new classobject
' neue Instanz der Klasse erzeugen
Dim pProduct As C_DocStructureObject
Set pProduct = New C_DocStructureObject
On Error Resume Next
With pProduct
' #########################################
'
' ..add your code here..
' ..füge hier deinen code ein..
'
' EXAMPLE:
' - add/uncomment this line in >C_DocStructureObject< -
' Public NomCla As String
'
' - add/uncomment this line >here< -
' .NomCla = iProduct.Nomenclature
' #########################################
' get the product itself
' das Product selbst aufnehmen
Set .Product = iProduct
' Name / PartNumber
.Name = iProduct.Name
.PartNumber = iProduct.PartNumber
' Type, either "Product" or "Part"
.DocType = ProductType(iProduct)
' checks if product is a component
' überprüft, ob das Product eine Component ist
.IsComponent = IsComp2(iProduct)
' Product/Part Reference
'#####################
Dim TS_Backup As Collection
Set TS_Backup = New Collection
With CATIA.ActiveDocument.Selection
For i = 1 To .Count
TS_Backup.Add .Item(i)
Next i
End With
'#####################
Dim TS As Selection: Set TS = MainProductDoc.Selection: TS.Clear
TS.Add iProduct
Set .Reference = TS.Item(1).Reference
.RefPath = TS.Item(1).Reference.DisplayName
'#####################
With CATIA.ActiveDocument.Selection
.Clear
For i = 1 To TS_Backup.Count
.Add TS_Backup.Item(i).Value
Next i
End With
'#####################
' sub-products count, Names, PartNumbers
.SubProductsCount = iProduct.Products.Count
Dim SPN As String: SPN = vbNullString
Dim SPPN As String: SPPN = vbNullString
For i = 1 To iProduct.Products.Count
If SPN = vbNullString Then SPN = iProduct.Products.Item(i).Name _
Else SPN = SPN & "^" & iProduct.Products.Item(i).Name
Next i
.SubProductsN = SPN
For i = 1 To iProduct.Products.Count
If SPPN = vbNullString Then SPPN = iProduct.Products.Item(i).PartNumber _
Else SPPN = SPPN & "^" & iProduct.Products.Item(i).PartNumber
Next i
.SubProductsPN = SPPN
' layer
.layer = layer
' FileName and FilePath
If iProduct Is MainProductDoc.Product Then
.FileName = MainProductDoc.Name
.FilePath = MainProductDoc.Path
Else
' you cannot get the filename from iProduct directly _
' but you can look for iProduct in pDocuments using _
' the Partnumber. fDocument then holds Filename and -path
For Each fDocument In pDocuments
If fDocument.Product.PartNumber = iProduct.PartNumber Then
.FileName = fDocument.Name
.FilePath = fDocument.Path
Exit For
End If
Next fDocument
End If
End With
' add current pProduct to collection
' aktuelles pProduct zu Collection hinzufügen
If Err.Number = 0 Then
pProducts.Add pProduct
End If
End Sub
'#########################################################
'#########################################################
'#########################################################
'#########################################################
'----------------------------
' CATMain() - Start Function -
'=========================================================
Public Sub CATMain()
Dim i As Integer
' get active document
' aktives Dokument definieren
On Error Resume Next
Set MainProductDoc = CATIA.ActiveDocument
If Err.Number <> 0 Then
' in case no document was found
' falls keine Dokument gefunden wurde
Call MsgBox(MsgStr_NoDocs_EN & Chr(10) & _
MsgStr_NoDocs_DE, vbInformation)
' exit macro
End
End If
On Error GoTo 0
' init variables
Dim PreSelections As Collection
Set PreSelections = New Collection
Set pProducts = New Collection
Set pDocuments = New Collection
' collection with documents (only Parts and Products)
' Collection mit documents (nur Parts und Products)
With CATIA.Documents
For i = 1 To .Count
If TypeName(.Item(i)) = "ProductDocument" _
Or TypeName(.Item(i)) = "PartDocument" Then _
pDocuments.Add .Item(i)
Next i
End With
' save currently selected objects
' speichern der ausgewählten Objekte
For i = 1 To MainProductDoc.Selection.Count
PreSelections.Add MainProductDoc.Selection.Item(i).Value
Next i
' add active document, because function DocStructure wont
' Actives Dokument aufnehmen weil es von der Funktion _
' DocStructure nicht aufgenommen wird
Call CreateDocStructureObject(MainProductDoc.Product)
' "layer" is the document-level the script is currently on
' "layer" bezeichnet die Dokumentenebene, auf der sich das _
' Programm gerade befindet
Dim s_layer As Integer: s_layer = 1
' "mark" marks the current position on a layer
' "mark" dient zum Verfolgen der aktuellen Position auf dem _
' jeweiligen "layer"
Dim s_mark() As Integer: ReDim s_mark(s_layer): s_mark(s_layer) = 1
' call recursive function to get the product structure
' rekursive Produkterkennung aufrufen
Call DocStructure(MainProductDoc.Product.Products, s_mark, s_layer)
' restore selected objects
' Wiederherstellen der Objekte
MainProductDoc.Selection.Clear
For i = 1 To PreSelections.Count
MainProductDoc.Selection.Add PreSelections.Item(i)
Next i
' DEBUG HERE
' ==========
'For i = 1 To pProducts.Count
' Debug.Print pProducts.Item(i).Product.Name
'Next i
End Sub
'----------------------------
' Doc_Structure:
' - recursive function to get the structure _
' of any assembly
' - rekursive Funktion zum Aufnehmen einer _
' beliebigen Baugruppe
'=========================================================
Private Function DocStructure(iProducts As Products, ByRef mark() As Integer, layer As Integer)
' grow "mark" if needed
' "mark" bei Bedarf erweitern
If UBound(mark) < layer Then
' grow "mark", if we go one level down
' "mark" erweitern, falls es eine Ebene tiefer ins Produkt geht
ReDim Preserve mark(layer)
' set "mark" to 1 in the new "layer"
' "mark" im neu erstellten "layer" auf 1 setzten
mark(layer) = 1
End If
' as long as there are products that haven't been checked
' solange noch Products da sind, die noch nicht untersucht wurden
If mark(layer) <= iProducts.Count Then
' create a class object that holds information about the _
' current product/part
' erstellt ein Klassenobjekt mit Informationen über das _
' momentane Product/Part
Call CreateDocStructureObject(iProducts.Item(mark(layer)))
' if the current product has subproducts go one level _
' deeper and call this function
' falls im ersten item der Products noch Unter-Products _
' sind, dann gehe eine Ebene tiefer und rufe diese _
' Funktion auf
If iProducts.Item(mark(layer)).Products.Count > 0 Then
Call DocStructure(iProducts.Item(mark(layer)).Products, mark, layer + 1)
' or else go one item further and call this function
' ansonsten gehe ein Item weiter und rufe diese _
' Function auf
Else
' if there are items left in the product
' falls im Product noch Items vorhanden sind
If mark(layer) < iProducts.Count Then
mark(layer) = mark(layer) + 1
Call DocStructure(iProducts, mark, layer)
' or else we go one level up again
' ansonsten gehen wir wieder eine Ebene zurück
Else
If layer >= 2 Then
mark(layer - 1) = mark(layer - 1) + 1
' reset "mark" on the lower levels
' "mark" auf den tieferen Ebenen wieder zurücksetzten
ReDim Preserve mark(layer - 1)
Call DocStructure(iProducts.Parent.Parent, mark, layer - 1)
Else
Exit Function
End If
End If
End If
' in case the last subproduct/subpart is reached
' falls wir beim letzten Unter-Product/Unter-Part angekommen sind
Else
If layer >= 2 Then
mark(layer - 1) = mark(layer - 1) + 1
' reset "mark" on the lower levels
' "mark" auf den tieferen Ebenen wieder zurücksetzten
ReDim Preserve mark(layer - 1)
Call DocStructure(iProducts.Parent.Parent, mark, layer - 1)
End If
End If
End Function
'----------------------------
' ProductType:
' - gets the product-type
' - ermittelt den Produkt-Typen
'=========================================================
Public Function ProductType(iProducts As Products) As String
Dim tryPart As Part
ProductType = "Product"
On Error Resume Next
Set tryPart = iProducts.Parent.ReferenceProduct.Parent.Part
If Err.Number = 0 Then ProductType = "Part"
On Error GoTo 0
End Function
'----------------------------
' IsComp:
' - checks if product is a component
' - überprüft, ob das Produkt eine Komponente ist
'=========================================================
Public Function IsComp(iProduct As Product) As Boolean
On Error Resume Next
Dim P1 As Product, P2 As Product
IsComp = True
Set P1 = iProduct.ReferenceProduct
' falls das Objekt keine Product ist, ist es auch
' keine Component
If Err.Number <> 0 Then
IsComp = False
Exit Function
End If
For Each fDocument In pDocuments
Set P2 = fDocument.Product
''If P1 Is P2 Then
If P1.PartNumber = P2.PartNumber And _
P1.Name = P2.Name Then
IsComp = False
Exit For
End If
Next
End Function
'----------------------------
' IsComp2 (by Little Cthulhu):
' - checks if product is a component
' - überprüft, ob das Produkt eine Komponente ist
'=========================================================
Public Function IsComp2(prdProductToCheck As Product) As Boolean
' check that product is not a root (otherwise it is definitely NOT component)
If (TypeOf prdProductToCheck.Parent Is Application) Then
' it is a root product and NOT a component
IsComp2 = False
Else
' check refernce product (where it is located)
''If (prdProductToCheck.ReferenceProduct Is prdProductToCheck.ReferenceProduct.Parent.Product) Then
If (prdProductToCheck.ReferenceProduct.PartNumber = prdProductToCheck.ReferenceProduct.Parent.Product.PartNumber) And _
(prdProductToCheck.ReferenceProduct.Name = prdProductToCheck.ReferenceProduct.Parent.Product.Name) Then
IsComp2 = False
Else
IsComp2 = True
End If
End If
End Function
'----------------------------
' FindParentProductDocument:
' - gets the parent product document (components are skipped)
' - findet das übergeordnete Produktdokument (das keine Komp. ist)
'=========================================================
Public Function FindParentProductDocument(iProduct As Product) As ProductDocument
Dim LoopCount As Integer: LoopCount = 0
Do
' nach 100 Objekten wird die Suche abgebrochen
If LoopCount > 100 Then Exit Do
Set iProduct = iProduct.Parent.Parent
LoopCount = LoopCount + 1
Loop While M_DocStructure.IsComp2(iProduct)
If LoopCount <= 100 Then
For Each fDocument In pDocuments
If fDocument.Product.PartNumber = iProduct.ReferenceProduct.PartNumber And _
fDocument.Product.Name = iProduct.ReferenceProduct.Name Then
Set FindParentProductDocument = fDocument
Exit For
End If
Next fDocument
End If
End Function
'----------------------------
' RemItemFromCollection:
' - removes an item from a collection
' - entfernt ein Objekt aus einer Collection
'=========================================================
Public Function RemItemFromCollection(iCollection As Collection, iPartNumber As String) As Boolean
Dim j As Integer
For j = 1 To pProducts.Count
If iCollection.Item(j).PartNumber = iPartNumber Then
iCollection.Remove j
Exit For
End If
Next j
RemItemFromCollection = True
End Function
Release Objects
Always good practice to release object variables when the macro ends. You can
Call ObjectsRelease
from a QueryClose – function for example.
Sub ObjectsRelease() On Error Resume Next ' public variables ... ' M_Doc_Structure Set MainProductDoc = Nothing Set pProducts = Nothing Set fProduct = Nothing Set pDocuments = Nothing Set fDocument = Nothing End Sub
Usage/Examples
You can
Call M_DocStructure.CATMain
from your CATMain() for example. After you call this line in your code you will have two public Collections (pProducts and pDocuments) which hold all Parts and Products in your ActiveDocument.
'macro: <macro-name> 'version: <macro-version> 'code: MSVBA 'purpose: ... 'author: ... 'date: ... 'copyright: ... '----------------------------------------------------------------------------- 'changes: ... '----------------------------------------------------------------------------- 'Option Explicit 'optional ... '---------------------------- ' CATMain '========================================================= Sub CATMain() ... ' Document Structure aufrufen Call M_DocStructure.CATMain ... End Sub
Module – M_PartProductRename
See Renaming a selected Part or Product (and most other Objects).
This method (compared to Little Cthulhu’s Script) relies on a recursive function to obtain the product structure. The disadvantage of recursive methods is the speed. The difference will be neglect-able on small and “normal” sized assemblies, very large assemblies with many hundred parts and products will significantly slow down the speed of the function.
' EN
'Public Const MsgStr_newName As String = "Enter a new Name:"
'Public Const MsgStr_newPartNumber As String = "Enter a new Partnumber:"
'Public Const SelStr As String = "Select any Object:"
' DE
Public Const MsgStr_newName As String = "Einen neuen Namen eingeben:"
Public Const MsgStr_newPartNumber As String = "Eine neue Teilenummer eingeben:"
Public Const SelStr As String = "Ein beliebiges Objekt auswählen:"
Sub CATMain()
' der String, der angehangen wird
Dim strZusatz As String
strZusatz = "_whatever"
'#######################################
Dim i As Integer
' recursive product structure
Call M_DocStructure.CATMain
Dim selection1 As Selection, selElement As Object
Set selection1 = MainProductDoc.Selection ': Selection1.Clear
'' Dim IOT(0): IOT(0) = "AnyObject" '"Product"
'' Dim strReturn As String
'' ' Benutzer soll ein Part oder ein Produkt auswählen
'' strReturn = Selection1.SelectElement2(IOT, SelStr, False)
'' If strReturn = "Normal" Then Set selElement = Selection1.Item(1).Value Else End
If selection1.Count = 0 Then
Call MsgBox("Es wurden keine Elemente ausgewählt.", vbExclamation)
End
End If
For i = 1 To selection1.Count
Set selElement = selection1.Item(i).Value
Select Case TypeName(selElement)
' -- FALLS DIE AUSWAHL EIN PRODUCT IST --
Case Is = "Product"
Dim curProduct As Product
Set curProduct = selElement
Dim curProductName As String
curProductName = curProduct.Name
' falls das ausgewählte Produkt das Root-Produkt ist
' Root-Produkt hat nur eine PartNumber, keinen Namen
If curProduct.ReferenceProduct Is MainProductDoc.Product Then
With MainProductDoc.Product
Call M_DocStructure.RemItemFromCollection(pProducts, .PartNumber)
.PartNumber = .PartNumber & strZusatz
Call M_DocStructure.CreateDocStructureObject(MainProductDoc.Product)
End With
Else
' finde Parent Product
Dim ParentProduct As Product
For Each fProduct In pProducts
If fProduct.Product Is curProduct Then
Set ParentProduct = fProduct.Product.Parent.Parent
Exit For
End If
Next
' überprüfen, ob ParentProduct eine Komponente ist
If M_DocStructure.IsComp2(ParentProduct) Then
Dim ParentProductDocument As ProductDocument
Set ParentProductDocument = M_DocStructure.FindParentProductDocument(curProduct)
Dim CSProduct As Product
Set CSProduct = ParentProductDocument.GetItem(ParentProduct.PartNumber).Products.Item(curProductName)
CSProduct.Name = CSProduct.Name & strZusatz
' falls ParentProduct ein normales Product ist
Else
' Dateiname ParentProduct
Dim ParentProductFileName As String
Dim ParentProductPartNumber As String
For Each fProduct In pProducts
If fProduct.Product Is ParentProduct Then
ParentProductFileName = fProduct.FileName
ParentProductPartNumber = fProduct.PartNumber
Exit For
End If
Next fProduct
'On Error Resume Next
With CATIA.Documents.Item(ParentProductFileName).Product.Products.Item(curProduct.Name)
Call M_DocStructure.RemItemFromCollection(pProducts, .PartNumber)
' Exemplarname
.Name = .Name & strZusatz
' Teilenummer
'.PartNumber = .PartNumber & strZusatz
Call M_DocStructure.CreateDocStructureObject(CATIA.Documents.Item(ParentProductFileName).Product.Products.Item(.Name))
End With
'On Error GoTo 0
End If
End If
' -- FALLS DIE AUSWAHL EIN PART IST --
Case Is = "Part"
Dim curPart As Part
Set curPart = selElement
'On Error Resume Next
For Each pProduct In pProducts
If curPart.Name = pProduct.PartNumber And Not pProduct.IsComponent Then
' Part hat nur eine PartNumber
pProduct.Product.PartNumber = pProduct.Product.PartNumber & strZusatz
Exit For
End If
Next pProduct
'On Error GoTo 0
' -- FALLS DIE AUSWAHL WEDER EIN PRODUCT NOCH EIN PART IST --
Case Else
On Error Resume Next
selElement.Name = selElement.Name & strZusatz
On Error GoTo 0
End Select
Next i
End Sub
You can also download the (ready-to-go) sample library VBA-PartProductRename.catvba.
Module – M_CountParts
'macro: <macro-name>
'version: <macro-version>
'code: MSVBA
'purpose: ...
'author: ...
'date: ...
'copyright: ...
'-----------------------------------------------------------------------------
'changes: ...
'-----------------------------------------------------------------------------
'Option Explicit 'optional
'----------------------------
' CATMain
'=========================================================
Sub CATMain()
' Document Structure aufrufen
Call M_DocStructure.CATMain
Dim part_counter As Integer
part_counter = 0
Dim PartsFound As Collection
Set PartsFound = New Collection
Dim PN As Variant
Dim PartFound As Boolean
Dim eachpart_PN() As String
Dim eachpart_count() As Integer
For i = 1 To pProducts.Count
Set fProduct = pProducts.Item(i)
If fProduct.DocType = "Part" Then
PartFound = False
For Each PN In PartsFound
If PN = fProduct.PartNumber Then
PartFound = True
For j = LBound(eachpart_PN) To UBound(eachpart_PN)
If eachpart_PN(j) = fProduct.PartNumber Then _
eachpart_count(j) = eachpart_count(j) + 1
Next
End If
Next
If PartFound = False Then
part_counter = part_counter + 1
PartsFound.Add fProduct.PartNumber
ReDim Preserve eachpart_PN(part_counter)
eachpart_PN(part_counter) = fProduct.PartNumber
ReDim Preserve eachpart_count(part_counter)
eachpart_count(part_counter) = 1
End If
End If
Next
' Ausgabe
Dim str As String
For i = 1 To UBound(eachpart_PN)
str = str & eachpart_PN(i) & " (" & CStr(eachpart_count(i)) & ")" & " ; "
Next
MsgBox "Im aktuellen Product befindet/befinden sich " & part_counter & " Part(s):" & Chr(10) & str
End Sub
Function – GetRootProduct
GetRootProduct is a sample function which makes use of these Collections to find the Root-Product of two Parts (part1 and part2). The Root-Product is needed for example to make constraints between part1 and part2 via VBA, because unlike the manual way (mouse clicks), in VBA CATIA doesn’t automatically put the constraints into the correct Product.. but more about (more complex) constraints between parts and products later.
(click on show source)
'----------------------------
' GetRootProduct:
' - finds the root-product of two parts
' - Findet das gemeinsame RootProduct von zwei Parts
'=========================================================
Public Function GetRootProduct(part1 As Part, part2 As Part) As Product
Dim i As Integer
Dim part1_found As Boolean, part2_found As Boolean
part1_found = False: part2_found = False
Dim part1_Ref As String, part2_Ref As String
Dim part1_ArrRef() As String
Dim part2_ArrRef() As String
' Document Structure
Call M_DocStructure.CATMain
For Each fProduct In pProducts
If fProduct.PartNumber = part1.Name Then
part1_found = True
part1_Ref = fProduct.RefPath
End If
If fProduct.PartNumber = part2.Name Then
part2_found = True
part2_Ref = fProduct.RefPath
End If
' wenn beide Parts gefunden wurden, kann die Schleife verlassen werden
If part1_found And part2_found Then Exit For
Next fProduct
part1_ArrRef = Split(part1_Ref, "/")
part2_ArrRef = Split(part2_Ref, "/")
Dim partArr_MinLength As Integer, partArr_Start As Integer
' kürzeres Array suchen und dessen Länge speichern
If UBound(part1_ArrRef) < UBound(part2_ArrRef) Then
partArr_MinLength = UBound(part1_ArrRef)
partArr_Start = LBound(part1_ArrRef)
Else
partArr_MinLength = UBound(part2_ArrRef)
partArr_Start = LBound(part2_ArrRef)
End If
Dim CRefPath As String
' prüfen bis wohin die Referenzen zu part1 und part2 gleich sind
For i = partArr_Start To partArr_MinLength
If part1_ArrRef(i) = part2_ArrRef(i) Then
CRefPath = CRefPath & part1_ArrRef(i) & "/"
Else
Exit For
End If
Next i
' anhand des ermittelten Referenz Pfads kann nun das gemeinsame Rootproduct von part1
' und part2 zurückgegeben werden
For Each fProduct In pProducts
If fProduct.RefPath = CRefPath Then
Set GetRootProduct = fProduct.Product
Exit For
End If
Next fProduct
' das Root Product selbst wird (noch) nicht gefunden, daher wird es hier manuell gesetzt
' falls es ausgewählt wurde
If GetRootProduct Is Nothing Then Set GetRootProduct = MainProductDoc.Product
End Function
U3D-2-PDF
Description & Download
MeshLab and MiKTeX make it possible to convert .STL and .WRL (VRML) – Files to 3D-PDF. U3D-2-PDF just automates the process explained at www.goermezer.de/content/view/486/616/ (3D-PDF kostenlos mit Open Source). .STL and .WRL (VRML) – Files can easily be exported by any common CAD-Software, normally without additional costs for licences.
You need to have
- (at least) the basic MiKTeX package
- MeshLab and
- .NET Framework 4
installed to get started (.NET Framework 4 can also be installed via Microsoft Update). If you do, go to the Download Page and get U3D-2-PDF.
Screenshots
This is a screenshot of the current version 0.0.3.0. You can set the paper layout either to DIN A4 or DIN A5 and the orientation to landscape or portrait. Leave the margins at 0 for a full-page 3D view.
3D settings…
The paths to MikTeX, MeshLab and Adobe Acrobat Reader are saved in an .ini file. You can edit those values here if necessary.
Screenshot of the previous version 0.0.2.0.
Representation of the original .stl file in 3D-Tool.
Include 3D Object in a LaTeX document
download cone-with-tex.pdf
You can easily include 3D objects created from .stl or .wrl files into your TeX documents. Here is an example of some LaTeX code I used for the example above.
%% Generated by the script %%
\documentclass[a4paper]{article}
\newcommand{\layout}{0}
\newcommand{\pname}{Cone.u3d}
\newcommand{\moviewidth}{190mm}
\newcommand{\movieheight}{157mm}
\usepackage[a4paper,portrait,top=20mm, bottom=-120mm, left=-10mm, right=-10mm]{geometry}
\usepackage[3D]{movie15}
\usepackage[colorlinks=false, pdfborder={0 0 0}]{hyperref}
\usepackage[UKenglish]{babel}
%% Custom Edit %%
\usepackage{german}
\usepackage[onehalfspacing]{setspace}
\usepackage{url}
%% Generated by the script %%
\begin{document}
\centering
%% Custom Edit %%
{\Huge Simple Cone} \\
\vspace{3mm}
%% Generated by the script %%
\includemovie[
poster,
toolbar,
label=\pname,
text=(\pname),
3Daac=60.000000, 3Droll=0.000000, 3Dc2c=0.004411 -0.158060 0.000000, 3Droo=0.158122, 3Dcoo=0.004411 0.010763 0.000000,
3Dlights=CAD,
]{\moviewidth}{\movieheight}{\pname}
%% Custom Edit %%
\vspace{5mm}
\begin{spacing}{2.5}
\begin{tabular}{l p{165mm}}
& {\Huge "`} {\Large {\it A cone is a three-dimensional geometric shape that tapers smoothly from a flat, usually circular base to a point called the apex or vertex. More precisely, it is the solid figure bounded by a plane base and the surface (called the lateral surface) formed by the locus of all straight line segments joining the apex to the perimeter of the base. The term "`cone"' sometimes refers just to the surface of this solid figure, or just to the lateral surface.}} {\Huge "'}
\end{tabular}
\end{spacing}
\begin{tabular}{p{65mm} l}
& {\large {\url{http://en.wikipedia.org/wiki/Cone_(geometry)}}}
\end{tabular}
%% Generated by the script %%
\end{document}
To Do
While making these screenshots I got this nice error.. it will be taken care of in the next release I hope.. it’s still beta (or maybe alpha).
- FIX ERRORS
add output format options- support for *.wrz – files (gzip compressed VRML files)
- multilingual support
Requirements:
Links/special Thanks:
- 3D-PDF kostenlos mit Open Source – Mustafa Görmezer
- GettyIcons
- SaviourMachine – Chris Scholten
- Adobe Acrobat Reader
- Cone.pdf [.pdf|16.38 kB] Not all PDF-Readers support 3D-PDF - Files (Adobe Arobat Reader does).
- Cone_Model-Files.zip [.zip|4.88 kB] .stl and .wrl model of a cone.
- U3D-2-PDF [.zip|384.93 kB] Automates the conversion of .stl or .wrl models to 3D-PDF via MiKTeX and MeshLab.
- cone-with-tex.pdf [.pdf|45.94 kB] 3D PDF file with additional text.

















