//===== // Xml header (for Script & Plugin Manager) in block comments // /* */ // //===== //===== // Import Statements // import BStandardDialog.Style; import BTextArea.WrapStyle; import BScrollPane.ScrollbarPolicy; import LayoutInfo.Alignment; import LayoutInfo.FillType; // //===== //===== // Create help components for future use. // helpButton = new BButton("Help & Info"); helpButton.addEventLink( CommandEvent.class, new Runnable(){ void run(){showHelpDialog();} }, "run" ); /* * When this method is called a neat help and information dialog is shown. */ showHelpDialog() { helpText = new BTextArea( "Description:\nThis tool places copies of an object you pick at specified destinations (positions and orientations) in space. Each of these destinations is specified by the position/orientation of another object in the scene. Each copy is actually placed at the destination object's location/orientation in the scene (click \"Object > Layout\" to see this), not necessarily where the object appears in the scene, if the particular object is of a type that can be seen. This is because the object's visible mesh can be offset from its local origin. I suggest using Null objects as destinations when its appropriate. Null objects are objects that have a position and orientation only and no mesh, so they only appear in the viewports (as intersecting line segments) and don't appear in renderings. Null objects can be created by clicking \"Object > Create Primitive > Null\" from the scene's menu bar.\n\nInstructions:\nBefore running this tool, simultaneously select in the scene both the object you want to copy AND the objects that will represent the places to copy to (destinations). If there are multiple destinations then the copies will end up grouped together (it groups by making them children of a new Null object that is created).\n\nTool Options:\n\"Object to copy\" List: On this list, highlight the object you want to make copies of. All others on this list will be destinations.\n\n\"Copy child objects too\" Checkbox: If the object to be copied has child objects, select this to include them in the whole process.\n\n\"Make copies be live duplicates of original\" Checkbox: Select this to have all copies be live duplicates of the original object (instead of stand-alone copies).\n\n\"Put grouping object at world origin\" Checkbox: Select this to place the object that the tool creates to group copies with (which is a Null object, by the way) at the scene's origin instead of at the average location of the copies. Then the copies will still be at the same place in the scene, but the object used to group them will be at the scene's origin.\n\nCredits:\nThis tool was made by John Burak but was originally created by heavily modifying most of the code from Julian MacDonald's Distribute script, and it has some code that was heavily modified from Yokiyoki's Text script (mainly just for how to do the help window), and some code modified from Peter Eastman's Array tool.", 400, 200 ); helpText.setEditable(false); helpText.setCaretPosition(0); helpText.setWrapStyle(BTextArea.WRAP_WORD); helpMessage = new BScrollPane(helpText, BScrollPane.SCROLLBAR_NEVER, BScrollPane.SCROLLBAR_AS_NEEDED); helpMessage.setPreferredViewSize(new Dimension(400,200)); helpMessage.setForceWidth(true); helpMessage.setForceHeight(true); helpDialog = new BStandardDialog("Help and Information", helpMessage, BStandardDialog.INFORMATION); helpDialog.showMessageDialog(window); } // //===== //===== // Get list of objects that are selected in the scene. // scene = window.getScene(); sceneSelection = scene.getSelection(); // //===== //===== // Check how many objects are selected - if too few then return with error dialog. // if (sceneSelection.length < 2) { tooFewSelectedErrorLabel = new BLabel("More than 1 object must be selected in the scene before running this tool."); tooFewSelectedErrorContainer = new ColumnContainer(); tooFewSelectedErrorContainer.add(tooFewSelectedErrorLabel); tooFewSelectedErrorContainer.add(helpButton); tooFewSelectedErrorDialog = new BStandardDialog("Copy to Location(s) Tool", tooFewSelectedErrorContainer, BStandardDialog.ERROR); tooFewSelectedErrorDialog.showMessageDialog(window); return; } // //===== //===== // Get a list of the currently selected objectInfo objects. // objectInfoList = new ObjectInfo[sceneSelection.length]; for(int i = 0; i < sceneSelection.length; i++) objectInfoList[i] = scene.getObject(sceneSelection[i]); // //===== //===== // Set up and show the main dialogue. // // Set up object name list for GUI objectNameList = new BList(); // Should parallel objectInfoList objectNameList.setMultipleSelectionEnabled(false); for(int i = 0; i < objectInfoList.length; i++) objectNameList.add(objectInfoList[i].name); objectNameList.setSelected(0,true); scrollableObjectNameList = new BScrollPane(objectNameList); scrollableObjectNameList.setPreferredViewSize(new Dimension(100, 100)); // set display size of object name list here scrollableObjectNameList.setForceWidth(true); // stretch out the list to fill the scroll pane scrollableObjectNameList.setForceHeight(true); // Set up check boxes makeLiveDuplicatesCheckBox = new BCheckBox(null, false); putGroupObjectAtWorldOriginCheckBox = new BCheckBox(null, false); copyChildrenCheckbox = new BCheckBox(null, true); // Build the container structure for most of the GUI objects final int textWidth = 50; // how many characters wide for text "labels" to be. final int rowSpaceing = 1; // how many lines to space between each row of GUI items (for readability of GUI) // Load all labels main GUI components here (must parallel inputWidgets list) Object[] mainWidgetTextLabels = { new BTextArea("Object to copy", 1, textWidth), new BTextArea("Copy child objects too",1, textWidth), new BTextArea("Make copies be live duplicates of original", 1, textWidth), new BTextArea("Put grouping object at world origin", 2, textWidth) }; // Load all main GUI components here (must parallel mainWidgetTextLabels list) Object[] mainWidgets = { scrollableObjectNameList, copyChildrenCheckbox, makeLiveDuplicatesCheckBox, putGroupObjectAtWorldOriginCheckBox }; // set up a two column container (actually a FormContainer) for most of the GUI components int mainWidgetCount = mainWidgets.length; twoColumnContainer = new FormContainer(2, mainWidgetCount*2); // twoColumnContainer will contains all the main components of the dialog. the "*2" is for the sake of leaving space between rows (readability) for(int i = 0; i < mainWidgetCount; i++) // loop through each row, putting each in the twoColumnContainer as we go. { mainWidgetTextLabels[i].setEditable(false); mainWidgetTextLabels[i].setWrapStyle(BTextArea.WRAP_WORD); mainWidgetTextLabels[i].setFocusable(false); mainWidgetTextLabels[i].setBackground(new java.awt.Color(128, 128, 128, 0) ); // the last zero make it a clear backround rowSpacer1 = new BTextArea("",rowSpaceing,0); rowSpacer1.setEditable(false); rowSpacer1.setFocusable(false); rowSpacer1.setBackground(new java.awt.Color(128, 128, 128, 0) ); //If the row spacers contained visible text (they are spacers, so they shouldn't, but if they did), we would need separate row spacers for each column to make them both show up. Not sure why. But just incase its helpful for spacers that don't contain text (like here), I'll do it here too. rowSpacer2 = new BTextArea("",rowSpaceing,0); rowSpacer2.setEditable(false); rowSpacer2.setFocusable(false); rowSpacer2.setBackground(new java.awt.Color(128, 128, 128, 0) ); twoColumnContainer.add(new BScrollPane(mainWidgetTextLabels[i]),0,(i*2), new LayoutInfo(LayoutInfo.EAST, LayoutInfo.NONE)); twoColumnContainer.add(rowSpacer1,0,(i*2)+1, new LayoutInfo(LayoutInfo.EAST, LayoutInfo.NONE)); // spacer twoColumnContainer.add(mainWidgets[i],1,(i*2), new LayoutInfo(LayoutInfo.WEST, LayoutInfo.NONE)); twoColumnContainer.add(rowSpacer2,1,(i*2)+1, new LayoutInfo(LayoutInfo.WEST, LayoutInfo.NONE)); // spacer } // Set up the outer-most container that will hold the twoColumnContainer and the help button finalContainer = new ColumnContainer(); finalContainer.add(twoColumnContainer); finalContainer.add(helpButton); // Actually display the main dialog dialog = new PanelDialog(window, "Copy to Location(s)", finalContainer); if (!dialog.clickedOk())//if they didn't click okay, return without doing anything return; // //===== //===== // Get choices from dialogue. // sourceObject = objectInfoList[ objectNameList.getSelectedIndex() ];//the object that gets copied copyChildren = copyChildrenCheckbox.getState(); makeLiveDuplicates = makeLiveDuplicatesCheckBox.getState(); putGroupObjectAtWorldOrigin = putGroupObjectAtWorldOriginCheckBox.getState(); // //----- //===== // Create a list of the destination objects (as ObjectInfo objects). // destinationObjectInfoList = new Vector();//this will list the objects that are destinations to copy to selectedObjectIndex = objectNameList.getSelectedIndex(); for(int i = 0; i < objectInfoList.length; i++) if(selectedObjectIndex != i) destinationObjectInfoList.add(objectInfoList[i]); // //===== //===== // If we are making multiple copies, then create a new object to group the copies under. // boolean thereAreMultipleDestinations = ( destinationObjectInfoList.size() > 1 ? true : false ); if(thereAreMultipleDestinations) { groupObject = new ObjectInfo(new NullObject(), new CoordinateSystem(), sourceObject.name + " copies group"); groupLocation = new Vec3(0,0,0); } // //===== //===== // Methods used to copy an object and its children to a new location // /* * Method to create a copy of an object and place it at CoordinateSystem cs. * If makeLiveDuplicates = true then make a live duplicate instead of a copy. * (Method originally by Peter Eastman, modified by John Burak.) */ private ObjectInfo createCopy(ObjectInfo objectToBeCopied, CoordinateSystem coordinateSystemIn) { // Get a transform matrix to go from coordinateSystemIn to objectToBeCopied's local coordinates Mat4 transform = coordinateSystemIn.fromLocal().times(objectToBeCopied.coords.toLocal()); return createCopy(objectToBeCopied, transform);//calls the other createCopy function (overloaded) } /* * Method to create a copy (or live duplicate) of an object, * tranform its coordinate system and add it to the group object. * (Method originally by Peter Eastman, modified by John Burak.) */ private ObjectInfo createCopy( ObjectInfo objectToBeCopied, Mat4 transform ) { ObjectInfo copiedObjectInfo = objectToBeCopied.duplicate(); if( !makeLiveDuplicates ) copiedObjectInfo.object = objectToBeCopied.object.duplicate(); copiedObjectInfo.coords.transformCoordinates(transform); window.addObject(copiedObjectInfo, null); // Add undo information here? if( copyChildren ) { for( int i = 0; i < objectToBeCopied.children.length; i++ ) { copiedObjectInfo.addChild(createChildCopy(objectToBeCopied.children[i], transform),i); } } return copiedObjectInfo; } /* * Method to create a copy (or live diplicate) of an object, add it to and tranform * its coordinate system. * (Method originally by Peter Eastman, modified by John Burak) */ private ObjectInfo createChildCopy(ObjectInfo objectToBeCopied, Mat4 transform) { ObjectInfo copiedObjectInfo = objectToBeCopied.duplicate(); if( !makeLiveDuplicates ) copiedObjectInfo.object = objectToBeCopied.object.duplicate(); copiedObjectInfo.coords.transformCoordinates(transform); window.addObject(copiedObjectInfo, null); for( int i=0; i < objectToBeCopied.children.length; i++ ) { copiedObjectInfo.addChild(createChildCopy(objectToBeCopied.children[i], transform),i); } return copiedObjectInfo; } // //===== //===== // Produce and set up the copies. // for(int i = 0; i < destinationObjectInfoList.size(); i++) // for each destination { CoordinateSystem destination = destinationObjectInfoList.get(i).coords;//.duplicate();//? objectInfoCopy = createCopy(sourceObject, destination); //add the copy object to the group if necessary if(thereAreMultipleDestinations) { groupObject.addChild(objectInfoCopy, groupObject.children.length); if(!putGroupObjectAtWorldOrigin) groupLocation.add(objectInfoCopy.coords.getOrigin()); // later we'll divide the components of the vector by numberOfCopies to finsih averaging the locations } } // //===== //===== // Add the group the scene if necessary. // if( thereAreMultipleDestinations ) { if( !putGroupObjectAtWorldOrigin ) // if we are putting the grouping null object at the average copy location { groupLocation.scale( 1.0 / (objectInfoList.length - 1) );//divide by the appropriate fraction to finish averaging the location groupObject.coords.setOrigin( groupLocation ); } window.addObject( groupObject, null ); } // //===== //===== // Rebulid the scene's item list because we changed it. // window.rebuildItemList(); // //=====