#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace adsk::core; using namespace adsk::fusion; using namespace adsk::cam; namespace { const double pi = 4.0* atan(1.0); } Ptr _app; Ptr _ui; Ptr _des; Ptr _cgGroups; Ptr _anchorPt; // Global const std::string _commandId = "CustomGraphicsSample_CPP"; const std::string _colorEffect_solid_id = "SolidColorEfect"; const std::string _colorEffect_basicMaterial_id = "BasicMaterialColorEffect"; const std::string _colorEffect_appearance_id = "AppearanceColorEffect"; const std::string _colorEffect_vertex_id = "VertexColorEffect"; const std::string _pointSetImage = "resources/16x16.png"; const std::string _solidLine_id = "Solid Line"; const std::string _centerLine_id = "Center Line"; const std::string _dashedLine_id = "Dashed Line"; const std::string _dotLine_id = "Dot Line"; const std::string _phantomLine_id = "Phantom Line"; const std::string _tracksLine_id = "Tracks Line"; const std::string _zigZagLine_id = "ZigZag Line"; int _numTeeth = 5; double _thickness = 0.5 * 2.54; double _scaleFactor = 10; // _scaleFactor is used to limit the size of pixel-scaled model // Global command inputs Ptr _customGraphicsObj; Ptr _colorEffects; Ptr _red; Ptr _green; Ptr _blue; Ptr _opacity; Ptr _glossiness; Ptr _selection; Ptr _transform; Ptr _materialLibList; Ptr _appearanceList; Ptr _appearanceFilter; Ptr _coordTable; Ptr _add; Ptr _addStrip; Ptr _delete; Ptr _isLineStrip; Ptr _lineStylePattern; Ptr _lineStyleWeight; Ptr _lineStyleScale; Ptr _viewPlacementGroup; Ptr _viewCorner; Ptr _viewScaleGroup; Ptr _pixelScale; Ptr _billboardingGroup; Ptr _billboardingStyle; Ptr _text; Ptr _textSize; Ptr _textStyle; Ptr _textFont; // Create the command definition. static Ptr createCommandDefinition() { Ptr commandDefinitions = _ui->commandDefinitions(); if (!commandDefinitions) return nullptr; // Be fault tolerant in case the command is already added. Ptr cmDef = commandDefinitions->itemById(_commandId); if (!cmDef) { cmDef = commandDefinitions->addButtonDefinition(_commandId, "CustomGraphicsSample", "Custom Graphics Sample"); } return cmDef; } // Add a row representing a coordinate (x, y, z) static void addRow(Ptr tableInput) { if (!tableInput) return; static size_t rowNumber = 0; std::stringstream rowId; rowId << rowNumber; Ptr tableChildInputs = tableInput->commandInputs(); Ptr xValueInput = tableChildInputs->addValueInput(tableInput->id() + "_x" + rowId.str(), "Value", "cm", ValueInput::createByReal(static_cast(rowNumber))); Ptr yValueInput = tableChildInputs->addValueInput(tableInput->id() + "_y" + rowId.str(), "Value", "cm", ValueInput::createByReal(static_cast(rowNumber))); Ptr zValueInput = tableChildInputs->addValueInput(tableInput->id() + "_z" + rowId.str(), "Value", "cm", ValueInput::createByReal(static_cast(rowNumber))); int row = tableInput->rowCount(); tableInput->addCommandInput(xValueInput, row, 0); tableInput->addCommandInput(yValueInput, row, 1); tableInput->addCommandInput(zValueInput, row, 2); rowNumber = rowNumber + 1; } static void addLineStrip(Ptr tableInput) { if (!tableInput) return; static size_t stripNumber = 0; std::stringstream stripId; stripId << stripNumber; Ptr tableChildInputs = tableInput->commandInputs(); Ptr strInput = tableChildInputs->addStringValueInput(tableInput->id() + "_strip" + stripId.str(), "Line Strip", "-- Line Strip --"); if (!strInput) return; strInput->isReadOnly(true); int row = tableInput->rowCount(); tableInput->addCommandInput(strInput, row, 0, 0, 2); stripNumber = stripNumber + 1; } static void replaceItems(Ptr cmdInput, std::vector newItems) { if (!cmdInput) return; Ptr listItems = cmdInput->listItems(); if (!listItems) return; listItems->clear(); Ptr itemNone = listItems->add("None", true); if (!itemNone) return; itemNone->isSelected(true); if (newItems.size() > 0) { for (std::string str : newItems) { listItems->add(str, false); } if (listItems->count() > 1) { Ptr item1 = listItems->item(1); Ptr item0 = listItems->item(0); // item "None" if (!item1 || !item0) return; item1->isSelected(true); item0->deleteMe(); } } } static std::vector getAppearancesFromLib(const std::string& libName, const std::string& filterExp) { std::vector appearanceList; static std::map> appearanceMap; if (appearanceMap.find(libName) != appearanceMap.end()) { appearanceList = appearanceMap[libName]; } else { if (!_app) return std::vector(); // get appearances according to libName Ptr matLibs = _app->materialLibraries(); if (!matLibs) return std::vector(); Ptr matLib = matLibs->itemByName(libName); if (!matLib) return std::vector(); Ptr appearances = matLib->appearances(); if (!appearances) return std::vector(); for (int i = 0; i < appearances->count(); ++i) { if(Ptr appear = appearances->item(i)) appearanceList.push_back(appear->name()); } appearanceMap[libName] = appearanceList; } // apply filter std::string lowerFilterExp(filterExp); if (!filterExp.empty()) { std::transform(filterExp.begin(), filterExp.end(), lowerFilterExp.begin(), ::tolower); std::vector filteredList; for (std::string appearanceName : appearanceList) { std::string lowerName(appearanceName); std::transform(appearanceName.begin(), appearanceName.end(), lowerName.begin(), ::tolower); if (lowerName.find(lowerFilterExp) != std::string::npos) { filteredList.push_back(appearanceName); } } appearanceList = filteredList; } return appearanceList; } static bool hasAppearance(Ptr lib) { if (!lib) return false; Ptr appearances = lib->appearances(); if (!appearances || appearances->count() == 0) return false; return true; } static std::vector getMaterialLibNames() { if (!_app) return std::vector(); Ptr libs = _app->materialLibraries(); if (!libs) return std::vector(); std::vector libNames; for (int i = 0; i < libs->count(); ++i) { if (Ptr lib = libs->item(i)) { if (hasAppearance(lib)) { libNames.push_back(lib->name()); } } } return libNames; } static Ptr getAppearance(const std::string& libName, const std::string& appearanceName) { if (appearanceName.empty() || appearanceName == "None" || !_app) return nullptr; if (!_des) return nullptr; Ptr appearances = _des->appearances(); if (appearances) { Ptr appearance = appearances->itemByName(appearanceName); if (appearance) return appearance; } Ptr libs = _app->materialLibraries(); if (!libs) return nullptr; Ptr lib = libs->itemByName(libName); if (!lib) return nullptr; appearances = lib->appearances(); if (!appearances) return nullptr; Ptr appearance = appearances->itemByName(appearanceName); return appearance; } static void applyLinesProperties(Ptr cgLines) { if (!cgLines) return; if (_lineStylePattern && _lineStylePattern->selectedItem()) { if (_lineStylePattern->selectedItem()->name() == _solidLine_id) cgLines->lineStylePattern(continuousLineStylePattern); else if (_lineStylePattern->selectedItem()->name() == _centerLine_id) cgLines->lineStylePattern(centerLineStylePattern); else if (_lineStylePattern->selectedItem()->name() == _dashedLine_id) cgLines->lineStylePattern(dashedLineStylePattern); else if (_lineStylePattern->selectedItem()->name() == _dotLine_id) cgLines->lineStylePattern(dotLineStylePattern); else if (_lineStylePattern->selectedItem()->name() == _dashedLine_id) cgLines->lineStylePattern(dashedLineStylePattern); else if (_lineStylePattern->selectedItem()->name() == _phantomLine_id) cgLines->lineStylePattern(phantomLineStylePattern); else if (_lineStylePattern->selectedItem()->name() == _tracksLine_id) cgLines->lineStylePattern(tracksLineStylePattern); else if (_lineStylePattern->selectedItem()->name() == _zigZagLine_id) cgLines->lineStylePattern(zigzagLineStylePattern); } if (_lineStyleWeight) cgLines->weight(static_cast(_lineStyleWeight->valueOne())); if (_lineStyleScale) cgLines->lineStyleScale(static_cast(_lineStyleScale->valueOne())); } static void applyColorEffect(Ptr cgEnt) { if (!_des) return; if (!_colorEffects) return; Ptr selected = _colorEffects->selectedItem(); if (!selected) return; std::string colorEffectName = selected->name(); Ptr colorEffect = nullptr; if (colorEffectName == _colorEffect_solid_id) { int red = 255, green = 0, blue = 0; if (_red) red = _red->valueOne(); if (_green) green = _green->valueOne(); if (_blue) blue = _blue->valueOne(); if (Ptr solidColor = Color::create(red, green, blue, 255)) { colorEffect = CustomGraphicsSolidColorEffect::create(solidColor); } } else if (colorEffectName == _colorEffect_basicMaterial_id) { Ptr diffuseColor = Color::create(0, 255, 0, 255); Ptr ambientColor = Color::create(255, 0, 0, 255); Ptr specularColor = Color::create(0, 0, 255, 255); Ptr emissiveColor = Color::create(0, 0, 0, 255); double glossiness = 5.0, opacity = 1.0; if (_glossiness) glossiness = _glossiness->valueOne(); if (_opacity) opacity = _opacity->valueOne(); if (diffuseColor && ambientColor && specularColor && emissiveColor) { colorEffect = CustomGraphicsBasicMaterialColorEffect::create(diffuseColor, ambientColor, specularColor, emissiveColor, glossiness, opacity); } } else if (colorEffectName == _colorEffect_appearance_id) { if (!_appearanceList || !_materialLibList) return; Ptr appearanceSelected = _appearanceList->selectedItem(); Ptr libSelected = _materialLibList->selectedItem(); if (!appearanceSelected || !libSelected) return; std::string appearanceName = appearanceSelected->name(); std::string libName = libSelected->name(); Ptr appearance = getAppearance(libName, appearanceName); if (appearance) { Ptr desAppearances = _des->appearances(); if (!desAppearances) return; if (!desAppearances->itemByName(appearanceName)) { appearance = desAppearances->addByCopy(appearance, appearanceName); } colorEffect = CustomGraphicsAppearanceColorEffect::create(appearance); } } else if (colorEffectName == _colorEffect_vertex_id) { colorEffect = CustomGraphicsVertexColorEffect::create(); } if (colorEffect && cgEnt) cgEnt->color(colorEffect); } static void getCoordinatesFromTable(Ptr tableInput, std::vector& vecCoords, std::vector& vecStripLen) { vecCoords.clear(); vecStripLen.clear(); if (_coordTable) { int stripLen = 0; for (int i = 0; i < _coordTable->rowCount(); ++i) { if (Ptr xValueInput = tableInput->getInputAtPosition(i, 0)) { Ptr yValueInput = tableInput->getInputAtPosition(i, 1); Ptr zValueInput = tableInput->getInputAtPosition(i, 2); if (yValueInput && zValueInput) { vecCoords.push_back(xValueInput->value()); vecCoords.push_back(yValueInput->value()); vecCoords.push_back(zValueInput->value()); ++stripLen; } } else if (Ptr lineStripInput = tableInput->getInputAtPosition(i, 0)) { vecStripLen.push_back(stripLen); stripLen = 0; } } vecStripLen.push_back(stripLen); } } static void changeColorEffectVisibility(const std::string& strColorEffectName) { if (_red) _red->isVisible(false); if (_green) _green->isVisible(false); if (_blue) _blue->isVisible(false); if (_opacity) _opacity->isVisible(false); if (_glossiness) _glossiness->isVisible(false); if (_appearanceList) _appearanceList->isVisible(false); if (_materialLibList) _materialLibList->isVisible(false); if (_appearanceFilter) _appearanceFilter->isVisible(false); if (strColorEffectName == _colorEffect_solid_id) { if (_red) _red->isVisible(true); if (_green) _green->isVisible(true); if (_blue) _blue->isVisible(true); } else if (strColorEffectName == _colorEffect_basicMaterial_id) { if (_opacity) _opacity->isVisible(true); if (_glossiness) _glossiness->isVisible(true); } else if (strColorEffectName == _colorEffect_appearance_id) { if (_appearanceList) _appearanceList->isVisible(true); if (_materialLibList) _materialLibList->isVisible(true); if (_appearanceFilter) _appearanceFilter->isVisible(true); } } static void changeLineStyleInputsVisibility(const std::string& patternName) { if (patternName == _solidLine_id) _lineStyleScale->isVisible(false); else _lineStyleScale->isVisible(true); } static void changeCGObjVisibility(const std::string& strObjName) { if (_colorEffects) { if (Ptr listItems = _colorEffects->listItems()) { listItems->clear(); listItems->add(_colorEffect_solid_id, true); listItems->add(_colorEffect_basicMaterial_id, false); listItems->add(_colorEffect_appearance_id, false); } _colorEffects->isVisible(false); } if (_selection) { _selection->clearSelection(); _selection->clearSelectionFilter(); _selection->setSelectionLimits(0, 0); _selection->isVisible(false); _selection->isEnabled(false); } if (_text) _text->isVisible(false); if (_coordTable) _coordTable->isVisible(false); if (_isLineStrip) _isLineStrip->isVisible(false); if (_lineStylePattern) _lineStylePattern->isVisible(false); if (_lineStyleWeight) _lineStyleWeight->isVisible(false); if (_lineStyleScale) _lineStyleScale->isVisible(false); changeColorEffectVisibility("None"); _viewPlacementGroup->isVisible(false); _viewScaleGroup->isVisible(false); _billboardingGroup->isVisible(false); if (strObjName == "Mesh") { if (_colorEffects) { _colorEffects->isVisible(true); if (Ptr listItems = _colorEffects->listItems()) { listItems->add(_colorEffect_vertex_id, false); } changeColorEffectVisibility(_colorEffect_solid_id); _viewPlacementGroup->isVisible(true); _viewScaleGroup->isVisible(true); _billboardingGroup->isVisible(true); } } else if (strObjName == "Lines") { changeColorEffectVisibility(_colorEffect_solid_id); _lineStylePattern->isVisible(true); _lineStyleWeight->isVisible(true); if (_lineStylePattern->selectedItem()->name() == _solidLine_id) { _lineStyleScale->isVisible(true); } _viewPlacementGroup->isVisible(true); _viewScaleGroup->isVisible(true); _billboardingGroup->isVisible(true); } else if (strObjName == "Curve") { if (_selection) { _selection->isVisible(true); _selection->isEnabled(true); _selection->tooltip("select a sketch curve"); _selection->commandPrompt("select a sketch curve"); _selection->addSelectionFilter("SketchCurve"); _selection->setSelectionLimits(1, 1); changeColorEffectVisibility(_colorEffect_solid_id); _lineStyleWeight->isVisible(true); } _viewPlacementGroup->isVisible(true); _viewScaleGroup->isVisible(true); _billboardingGroup->isVisible(true); } else if (strObjName == "BRep") { if (_colorEffects) _colorEffects->isVisible(true); if (_selection) { _selection->isVisible(true); _selection->isEnabled(true); _selection->tooltip("select a BRep body"); _selection->commandPrompt("select a BRep body"); _selection->addSelectionFilter("Bodies"); _selection->setSelectionLimits(1, 1); changeColorEffectVisibility(_colorEffect_solid_id); } _viewPlacementGroup->isVisible(true); _viewScaleGroup->isVisible(true); _billboardingGroup->isVisible(true); } else if (strObjName == "Text") { if (_text) _text->isVisible(true); if (_textSize) _textSize->isVisible(true); if (_textStyle) _textStyle->isVisible(true); if (_textFont) _textFont->isVisible(true); } else if (strObjName == "PointSet - Custom") { if (_coordTable) _coordTable->isVisible(true); if (_addStrip) _addStrip->isEnabled(false); } else if (strObjName == "Lines - Custom") { if (_coordTable) _coordTable->isVisible(true); if (_isLineStrip) _isLineStrip->isVisible(true); if (_addStrip) _addStrip->isEnabled(true); changeColorEffectVisibility(_colorEffect_solid_id); _lineStylePattern->isVisible(true); _lineStyleWeight->isVisible(true); if (_lineStylePattern->selectedItem()->name() == _solidLine_id) { _lineStyleScale->isVisible(true); } } } static Ptr rotate2D(double rad, Ptr vec) { if (!vec) return Vector2D::create(); double x = vec->x(); double y = vec->y(); double newX = x * cos(rad) - y * sin(rad); double newY = x * sin(rad) + y * cos(rad); return Vector2D::create(newX, newY); } static void calculateCoordinates(int numTeeth, /*out*/std::vector& rPts0, /*out*/std::vector& hPts0,/*out*/std::vector& pPts0,/*out*/std::vector& oPts0, /*out*/std::vector& rPts1, /*out*/std::vector& hPts1,/*out*/std::vector& pPts1,/*out*/std::vector& oPts1, /*out*/std::vector& vecCoords, /*out*/std::vector& vecColors) { if (numTeeth < 3) return; // holeDia < rootDia < pitchDia < outsideDia double holeDia = 0.5 * 2.54, diametralPitch = 2 / 2.54; double pitchDia = _numTeeth / diametralPitch; double dedendum = 1.157 / diametralPitch; if (fabs((20 * (pi / 180)) - diametralPitch) < 1e-6) { double circularPitch = pi / diametralPitch; if (circularPitch >= 20) dedendum = 1.25 / diametralPitch; else dedendum = (1.2 / diametralPitch) + (.002 * 2.54); } double rootDia = pitchDia - (2 * dedendum); double outsideDia = (_numTeeth + 2) / diametralPitch; Ptr vecRootRadi = Vector2D::create(rootDia / 2, 0); Ptr vecHoleRadi = Vector2D::create(holeDia / 2, 0); Ptr vecPitchRadi = Vector2D::create(pitchDia / 2, 0); Ptr vecOutRadi = Vector2D::create(outsideDia / 2, 0); double unitRadian = pi / numTeeth; for (int i = 0; i < 2 * numTeeth; ++i) { if (Ptr pos = rotate2D(unitRadian * (i - 0.5), vecRootRadi)) { double x = pos->x(), y = pos->y(); rPts0.push_back(static_cast(vecCoords.size() / 3)); rPts1.push_back(static_cast(vecCoords.size() / 3 + 1)); vecCoords.insert(vecCoords.end(), { x, y, 0, x, y, _thickness }); vecColors.insert(vecColors.end(), { 255,0,255,128, 255,0,255,128 }); } } for (int i = 0; i < 2 * numTeeth; ++i) { if (Ptr pos = rotate2D(unitRadian * (i - 0.5), vecHoleRadi)) { double x = pos->x(), y = pos->y(); hPts0.push_back(static_cast(vecCoords.size() / 3)); hPts1.push_back(static_cast(vecCoords.size() / 3 + 1)); vecCoords.insert(vecCoords.end(), { x, y, 0, x, y, _thickness }); vecColors.insert(vecColors.end(), { 255,0,0,128, 255,0,0,128 }); } } for (int i = 0; i < 2 * numTeeth; ++i) { if (Ptr pos = rotate2D(unitRadian * (i - 0.5), vecPitchRadi)) { double x = pos->x(), y = pos->y(); pPts0.push_back(static_cast(vecCoords.size() / 3)); pPts1.push_back(static_cast(vecCoords.size() / 3 + 1)); vecCoords.insert(vecCoords.end(), { x, y, 0, x, y, _thickness }); vecColors.insert(vecColors.end(), { 0,0,255,128, 0,0,255,128 }); } } for (int i = 0; i < numTeeth; ++i) { if (Ptr pos = rotate2D(unitRadian * i * 2, vecOutRadi)) { double x = pos->x(), y = pos->y(); oPts0.push_back(static_cast(vecCoords.size() / 3)); oPts1.push_back(static_cast(vecCoords.size() / 3 + 1)); vecCoords.insert(vecCoords.end(), { x, y, 0, x, y, _thickness }); vecColors.insert(vecColors.end(), { 0,255,255,128, 0,255,255,128 }); } } } static std::vector calculateStripLen(int numTeeth) { if (numTeeth < 3) return std::vector(); std::vector vecStripLen; for (int i = 0; i < numTeeth; ++i) vecStripLen.push_back(6); for (int i = 0; i < 2*numTeeth; ++i) vecStripLen.push_back(21); for (int i = 0; i < numTeeth; ++i) vecStripLen.push_back(24); for (int i = 0; i < 2*numTeeth; ++i) vecStripLen.push_back(6); return vecStripLen; } static std::vector calculateTriangles(int numTeeth, std::vector rPts0, std::vector hPts0, std::vector pPts0, std::vector oPts0, std::vector rPts1, std::vector hPts1, std::vector pPts1, std::vector oPts1) { if (numTeeth < 3) return std::vector(); std::vector vertexIndexList; // triangles between teeth for (int i = 0; i < numTeeth; ++i) { int idx0 = (2 * i + 1) % (2 * numTeeth); int idx1 = (2 * i + 2) % (2 * numTeeth); int rPtA0 = rPts0[idx0]; int rPtB0 = rPts0[idx1]; int rPtA1 = rPts1[idx0]; int rPtB1 = rPts1[idx1]; vertexIndexList.insert(vertexIndexList.end(), { rPtA0,rPtB0,rPtB1, rPtB1,rPtA1,rPtA0 }); } // triangles on surface0 for (int i = 0; i < numTeeth; ++i) { int rPtA = rPts0[i * 2]; int rPtB = rPts0[i * 2 + 1]; int rPtC = rPts0[(i * 2 + 2) % (2 * numTeeth)]; int hPtA = hPts0[i * 2]; int hPtB = hPts0[i * 2 + 1]; int hPtC = hPts0[(i * 2 + 2) % (2 * numTeeth)]; int pPtA = pPts0[i * 2]; int pPtB = pPts0[i * 2 + 1]; int oPt = oPts0[i]; vertexIndexList.insert(vertexIndexList.end(), { hPtB,hPtC,rPtC, rPtC,rPtB,hPtB, rPtA,rPtB,pPtB, pPtB,pPtA,rPtA, hPtA,hPtB,rPtB, rPtB,rPtA,hPtA, pPtA,pPtB,oPt }); } // triangles on surface1 for (int i = 0; i < numTeeth; ++i) { int rPtA = rPts1[i * 2]; int rPtB = rPts1[i * 2 + 1]; int rPtC = rPts1[(i * 2 + 2) % (2 * numTeeth)]; int hPtA = hPts1[i * 2]; int hPtB = hPts1[i * 2 + 1]; int hPtC = hPts1[(i * 2 + 2) % (2 * numTeeth)]; int pPtA = pPts1[i * 2]; int pPtB = pPts1[i * 2 + 1]; int oPt = oPts1[i]; vertexIndexList.insert(vertexIndexList.end(), { hPtC,hPtB,rPtB, rPtB,rPtC,hPtC, rPtB,rPtA,pPtA, pPtA,pPtB,rPtB, hPtB,hPtA,rPtA, rPtA,rPtB,hPtB, pPtB,pPtA,oPt }); } // triangles on teeth for (int i = 0; i < numTeeth; ++i) { int rPtA0 = rPts0[i * 2]; int rPtB0 = rPts0[i * 2 + 1]; int pPtA0 = pPts0[i * 2]; int pPtB0 = pPts0[i * 2 + 1]; int rPtA1 = rPts1[i * 2]; int rPtB1 = rPts1[i * 2 + 1]; int pPtA1 = pPts1[i * 2]; int pPtB1 = pPts1[i * 2 + 1]; int oPt0 = oPts0[i]; int oPt1 = oPts1[i]; vertexIndexList.insert(vertexIndexList.end(), { rPtA1, rPtA0, pPtA0, pPtA0, pPtA1, rPtA1, pPtA1, pPtA0, oPt0, oPt0, oPt1, pPtA1, rPtB0, rPtB1, pPtB1, pPtB1, pPtB0, rPtB0, pPtB0, pPtB1, oPt1, oPt1, oPt0, pPtB0 }); } // triangles on inner face for (int i = 0; i < 2 * numTeeth; ++i) { int hPtA0 = hPts0[i]; int hPtB0 = hPts0[(i + 1) % (2 * numTeeth)]; int hPtA1 = hPts1[i]; int hPtB1 = hPts1[(i + 1) % (2 * numTeeth)]; vertexIndexList.insert(vertexIndexList.end(), { hPtA1,hPtB1,hPtB0, hPtB0,hPtA0,hPtA1 }); } return vertexIndexList; } static Ptr drawMesh(const Ptr& cgGroup) { // Calculate mesh coordinates std::vector rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1; std::vector vecColors; std::vector vecCoords; calculateCoordinates(_numTeeth, rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1, vecCoords, vecColors); Ptr coordinates = CustomGraphicsCoordinates::create(vecCoords); if (!coordinates) return nullptr; coordinates->colors(vecColors); // Calculate mesh triangles std::vector vertexIndexList = calculateTriangles(_numTeeth, rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1); // Add Custom Graphics mesh if (!cgGroup) return nullptr; return cgGroup->addMesh(coordinates, vertexIndexList, std::vector(), std::vector()); } static Ptr drawLines(const Ptr& cgGroup) { if (!cgGroup) return nullptr; // Calculate lines coordinates std::vector rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1; std::vector vecColors; std::vector vecCoords; calculateCoordinates(_numTeeth, rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1, vecCoords, vecColors); Ptr coordinates = CustomGraphicsCoordinates::create(vecCoords); if (!coordinates) return nullptr; // Calculate lines triangles std::vector vertexIndexList = calculateTriangles(_numTeeth, rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1); // Calculate lines strip length std::vector vecStripLen = calculateStripLen(_numTeeth); Ptr cgLines = cgGroup->addLines(coordinates, vertexIndexList, true, vecStripLen); return cgLines; } static Ptr drawPointSet(const Ptr& cgGroup) { if (!cgGroup) return nullptr; // Calculate coordinates std::vector rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1; std::vector vecColors; std::vector vecCoords; calculateCoordinates(_numTeeth, rPts0, hPts0, pPts0, oPts0, rPts1, hPts1, pPts1, oPts1, vecCoords, vecColors); Ptr coordinates = CustomGraphicsCoordinates::create(vecCoords); if (!coordinates) return nullptr; return cgGroup->addPointSet(coordinates, std::vector(), UserDefinedCustomGraphicsPointType, _pointSetImage); } // CommandExecuted event handler. class OnExecuteEventHandler : public adsk::core::CommandEventHandler { public: void notify(const Ptr& eventArgs) override { // get selection entity first since it's fragile and any creation/edit operations will clear the selection. Ptr selEntity = nullptr; if (_selection && _selection->selectionCount() > 0) { if (Ptr sel0 = _selection->selection(0)) { selEntity = sel0->entity(); } } if (_customGraphicsObj) { if (!_cgGroups) return; Ptr cgGroup = _cgGroups->add(); if (!cgGroup) return; if (!_anchorPt) _anchorPt = Point3D::create(); Ptr cgEnt = nullptr; Ptr selectedCGObj = _customGraphicsObj->selectedItem(); if (!selectedCGObj) return; std::string cgObjName = selectedCGObj->name(); if (cgObjName == "Mesh") { cgEnt = drawMesh(cgGroup); _anchorPt->setWithArray({ 0, 0, _thickness / 2 }); } else if (cgObjName == "Lines") { cgEnt = drawLines(cgGroup); _anchorPt->setWithArray({ 0, 0, _thickness / 2 }); applyLinesProperties(cgEnt); } else if (cgObjName == "PointSet") { cgEnt = drawPointSet(cgGroup); } else if (cgObjName == "BRep") { if (Ptr body = selEntity->cast()) { cgEnt = cgGroup->addBRepBody(body); } } else if (cgObjName == "Curve") { if (Ptr skCurve = selEntity->cast()) { if (Ptr sk = skCurve->parentSketch()) { Ptr curv = nullptr; if (Ptr skArc = skCurve->cast()) curv = skArc->geometry(); else if (Ptr skEllipArc = skCurve->cast()) curv = skEllipArc->geometry(); else if (Ptr skCircle = skCurve->cast()) curv = skCircle->geometry(); else if (Ptr skEllipse = skCurve->cast()) curv = skEllipse->geometry(); else if (Ptr skLine = skCurve->cast()) curv = skLine->geometry(); else if (Ptr skSpline = skCurve->cast()) curv = skSpline->geometry(); if (curv) { curv->transformBy(sk->transform()); Ptr cgCurve = cgGroup->addCurve(curv); cgEnt = cgCurve; if (cgCurve) cgCurve->weight(static_cast(_lineStyleWeight->valueOne())); } } } } else if (cgObjName == "Text") { if (_text) { std::string font = _textFont ? _textFont->value() : "Arial"; double size = _textSize ? _textSize->value() : 1.0; cgEnt = cgGroup->addText(_text->value(), font, size, Matrix3D::create()); if (!cgEnt) cgEnt = cgGroup->addText(_text->value(), "Arial", size, Matrix3D::create()); Ptr cgText = cgEnt; if (cgText && _textStyle) { Ptr items = _textStyle->listItems(); if (items) { for (size_t i = 0; i < items->count(); ++i) { Ptr item = items->item(i); if (!item) continue; if (item->name() == "Bold") cgText->isBold(item->isSelected()); else if (item->name() == "Italic") cgText->isItalic(item->isSelected()); else if (item->name() == "UnderLine") cgText->isUnderline(item->isSelected()); else if (item->name() == "StrikeThrough") cgText->isStrikeThrough(item->isSelected()); } } } } } else if (cgObjName == "PointSet - Custom") { if (_coordTable) { std::vector vecCoords; std::vector vecStripLen; getCoordinatesFromTable(_coordTable, vecCoords, vecStripLen); Ptr coordinates = CustomGraphicsCoordinates::create(vecCoords); cgEnt = cgGroup->addPointSet(coordinates, std::vector(), UserDefinedCustomGraphicsPointType, _pointSetImage); } } else if (cgObjName == "Lines - Custom") { if (_coordTable) { std::vector vecCoords; std::vector vecStripLen; getCoordinatesFromTable(_coordTable, vecCoords, vecStripLen); Ptr coordinates = CustomGraphicsCoordinates::create(vecCoords); bool isLineStrip = true; if (_isLineStrip) isLineStrip = _isLineStrip->value(); cgEnt = cgGroup->addLines(coordinates, std::vector(), isLineStrip, vecStripLen); applyLinesProperties(cgEnt); } } // add attributes to the custom graphics entity if (cgEnt) { // color effect if (!cgEnt->cast() && !cgEnt->cast()) // do not apply effect to point set and text node applyColorEffect(cgEnt); // transform Ptr transMat = Matrix3D::create(); double transformDistance = 1.0; if (_transform) transformDistance = _transform->value(); Ptr origin = Point3D::create(transformDistance, 0, 0); if (transMat && origin) { transMat->setWithCoordinateSystem(origin, Vector3D::create(1, 0, 0), Vector3D::create(0, 1, 0), Vector3D::create(0, 0, 1)); cgEnt->transform(transMat); } // calculate _scaleFactor and _anchorPt for viewPlacement, viewScale and billboarding attributes based on the bounding box of custom graphics entity if (Ptr bbox = cgEnt->boundingBox()) { Ptr maxPt = bbox->maxPoint(); Ptr minPt = bbox->minPoint(); if (maxPt && minPt) { _scaleFactor = 100 / minPt->distanceTo(maxPt); _anchorPt->setWithArray({ (minPt->x() + maxPt->x()) / 2, (minPt->y() + maxPt->y()) / 2, (minPt->z() + maxPt->z()) / 2 }); } } // view placement if (_viewPlacementGroup && _viewPlacementGroup->isVisible() && _viewPlacementGroup->isEnabledCheckBoxChecked() && _viewCorner && _viewCorner->selectedItem()) { Ptr viewPt = Point2D::create(100, 100); // upper left corner by default ViewCorners corner = ViewCorners::upperLeftViewCorner; Ptr selected = _viewCorner->selectedItem(); if (selected->name() == "Upper Right") corner = ViewCorners::upperRightViewCorner; else if (selected->name() == "Lower Left") corner = ViewCorners::lowerLeftViewCorner; else if (selected->name() == "Lower Right") corner = ViewCorners::lowerRightViewCorner; Ptr attr = CustomGraphicsViewPlacement::create(_anchorPt, corner, viewPt); cgEnt->viewPlacement(attr); } // view scale if (_viewScaleGroup && _viewScaleGroup->isVisible() && _viewScaleGroup->isEnabledCheckBoxChecked() && _pixelScale) { Ptr attr = CustomGraphicsViewScale::create(_scaleFactor * _pixelScale->valueOne(), _anchorPt); cgEnt->viewScale(attr); } // billboarding if (_billboardingGroup && _billboardingGroup->isVisible() && _billboardingGroup->isEnabledCheckBoxChecked() && _billboardingStyle && _billboardingStyle->selectedItem()) { // screen style by default CustomGraphicsBillBoardStyles bbStyle = CustomGraphicsBillBoardStyles::ScreenBillBoardStyle; Ptr selected = _billboardingStyle->selectedItem(); if (selected->name() == "Axis") bbStyle = CustomGraphicsBillBoardStyles::AxialBillBoardStyle; else if (selected->name() == "Right Reading") bbStyle = CustomGraphicsBillBoardStyles::RightReadingBillBoardStyle; Ptr attr = CustomGraphicsBillBoard::create(_anchorPt); attr->axis(Vector3D::create(0, 1, 0)); attr->billBoardStyle(bbStyle); cgEnt->billBoarding(attr); } } } } }; // InputChange event handler. class OnInputChangedEventHander : public adsk::core::InputChangedEventHandler { public: void notify(const Ptr& eventArgs) override { if (!eventArgs) return; Ptr changedInput = eventArgs->input(); if (!changedInput) return; std::string changedInputId = changedInput->id(); if (changedInputId == _commandId + "_cgObj") { if (_customGraphicsObj) { if (Ptr selectedItem = _customGraphicsObj->selectedItem()) { changeCGObjVisibility(selectedItem->name()); } } } else if (changedInputId == _commandId + "_colorEffects") { if (_colorEffects) { if (Ptr selectedItem = _colorEffects->selectedItem()) { changeColorEffectVisibility(selectedItem->name()); } } } else if (changedInputId == _commandId + "_appearanceFilter" || changedInputId == _commandId + "_materialLib") { std::string libName(""), filterExp(""); if (_materialLibList) { if (Ptr selectedItem = _materialLibList->selectedItem()) { libName = selectedItem->name(); } } if (_appearanceFilter) { filterExp = _appearanceFilter->value(); } std::vector appearanceNames = getAppearancesFromLib(libName, filterExp); if (_appearanceList) { replaceItems(_appearanceList, appearanceNames); } } else if (_coordTable && changedInputId == _coordTable->id() + "_add") { addRow(_coordTable); } else if (_coordTable && changedInputId == _coordTable->id() + "_addStrip") { addLineStrip(_coordTable); } else if (_coordTable && changedInputId == _coordTable->id() + "_delete") { int selectedRowNo = _coordTable->selectedRow(); if (selectedRowNo == -1) { _ui->messageBox("Select one row to delete"); } else { _coordTable->deleteRow(selectedRowNo); } } else if (_lineStylePattern && changedInputId == _commandId + "_LSPattern") { changeLineStyleInputsVisibility(_lineStylePattern->selectedItem()->name()); } } }; // CommandDestroyed event handler class OnDestroyEventHandler : public adsk::core::CommandEventHandler { public: void notify(const Ptr& eventArgs) override { adsk::terminate(); } }; // CommandCreated event handler. class CommandCreatedEventHandler : public adsk::core::CommandCreatedEventHandler { public: void notify(const Ptr& eventArgs) override { if (eventArgs) { Ptr command = eventArgs->command(); if (command) { Ptr onDestroy = command->destroy(); if (!onDestroy) return; bool isOk = onDestroy->add(&onDestroyHandler_); if (!isOk) return; Ptr onInputChanged = command->inputChanged(); if (!onInputChanged) return; isOk = onInputChanged->add(&onInputChangedHandler_); if (!isOk) return; Ptr onExecute = command->execute(); if (!onExecute) return; isOk = onExecute->add(&onExecuteHandler_); if (!isOk) return; Ptr onExecutePtrview = command->executePreview(); if (!onExecutePtrview) return; isOk = onExecutePtrview->add(&onExecuteHandler_); if (!isOk) return; Ptr inputs = command->commandInputs(); if (!inputs) return; // menu for different kinds of custom graphics _customGraphicsObj = inputs->addDropDownCommandInput(_commandId + "_cgObj", "Custom Graphics Object", DropDownStyles::TextListDropDownStyle); if (_customGraphicsObj) { Ptr listItems = _customGraphicsObj->listItems(); if (listItems) { listItems->add("Mesh", true); listItems->add("Lines", false); listItems->add("PointSet", false); listItems->add("Curve", false); listItems->add("BRep", false); listItems->add("Text", false); listItems->add("Lines - Custom", false); listItems->add("PointSet - Custom", false); } } // coordinates table used by 'Lines - Custom' and 'PointSet - Custom' _coordTable = inputs->addTableCommandInput(_commandId + "_table", "Coordinates Table", 3, "1:1:1"); if (_coordTable) { _coordTable->maximumVisibleRows(10); addRow(_coordTable); Ptr addButtonInput = inputs->addBoolValueInput(_coordTable->id() + "_add", "Add", false, "", true); if (addButtonInput) { _coordTable->addToolbarCommandInput(addButtonInput); addButtonInput->isVisible(false); } Ptr addStripButtonInput = inputs->addBoolValueInput(_coordTable->id() + "_addStrip", "Add Strip", false, "", true); if (addStripButtonInput) { _coordTable->addToolbarCommandInput(addStripButtonInput); addStripButtonInput->isVisible(false); } Ptr deleteButtonInput = inputs->addBoolValueInput(_coordTable->id() + "_delete", "Delete", false, "", true); if (deleteButtonInput) { _coordTable->addToolbarCommandInput(deleteButtonInput); deleteButtonInput->isVisible(false); } _coordTable->isVisible(false); } // specific for 'Lines - Custom' _isLineStrip = inputs->addBoolValueInput(_commandId + "_isLineStrip", "Use LineStrip", true, "", true); if (_isLineStrip) { _isLineStrip->isVisible(false); } // color effects for custom graphics Mesh/BRep _colorEffects = inputs->addDropDownCommandInput(_commandId + "_colorEffects", "Color Effect", DropDownStyles::TextListDropDownStyle); if (_colorEffects) { Ptr listItems = _colorEffects->listItems(); if (listItems) { listItems->add(_colorEffect_solid_id, true); listItems->add(_colorEffect_basicMaterial_id, false); listItems->add(_colorEffect_appearance_id, false); listItems->add(_colorEffect_vertex_id, false); } } // RGB for solid colors _red = inputs->addIntegerSliderCommandInput(_commandId + "_red", "Red", 0, 255); if (_red) _red->valueOne(255); _green = inputs->addIntegerSliderCommandInput(_commandId + "_green", "Green", 0, 255); if (_green) _green->valueOne(0); _blue = inputs->addIntegerSliderCommandInput(_commandId + "_blue", "Blue", 0, 255); if (_blue) _blue->valueOne(0); // specific for basic material color effect _glossiness = inputs->addFloatSliderCommandInput(_commandId + "_glossiness", "Glossiness", "", 0, 128); if (_glossiness) { _glossiness->valueOne(128); _glossiness->isVisible(false); } _opacity = inputs->addFloatSliderCommandInput(_commandId + "_opacity", "Opacity", "", 0, 1); if (_opacity) { _opacity->valueOne(1); _opacity->isVisible(false); } // for appearance color effect std::string defaultMatLibName(""); _materialLibList = inputs->addDropDownCommandInput(_commandId + "_materialLib", "Material Library", DropDownStyles::TextListDropDownStyle); if (_materialLibList) { Ptr listItems = _materialLibList->listItems(); if (listItems) { std::vector matLibNames = getMaterialLibNames(); for (std::string libName : matLibNames) { listItems->add(libName, false); } if (listItems->count() > 0) { Ptr item0 = listItems->item(0); if (item0) { item0->isSelected(true); defaultMatLibName = item0->name(); } } } _materialLibList->isVisible(false); } _appearanceList = inputs->addDropDownCommandInput(_commandId + "_appearanceList", "Appearance", DropDownStyles::TextListDropDownStyle); if (_appearanceList && !defaultMatLibName.empty()) { Ptr listItems = _appearanceList->listItems(); if (listItems) { std::vector defaultAppearanceList = getAppearancesFromLib(defaultMatLibName, ""); for (std::string appearanceName : defaultAppearanceList) { listItems->add(appearanceName, false); } if (listItems->count() > 0) { Ptr item0 = listItems->item(0); if (item0) { item0->isSelected(true); } } } _appearanceList->isVisible(false); } _appearanceFilter = inputs->addStringValueInput(_commandId + "_appearanceFilter", "Filter"); if (_appearanceFilter) { _appearanceFilter->isVisible(false); } // selection input for custom graphics BRep/Curve _selection = inputs->addSelectionInput(_commandId + "_sel", "Selection", ""); if (_selection) { _selection->setSelectionLimits(0, 1); _selection->isVisible(false); _selection->isEnabled(false); } // for custom graphics text std::string txt = "{standard text}\\P{\\H1.5x;height:1.5x}\\P{\\C1;color:red}\\P{\\H1;height:1 unit}\\P{\\T2;char spacing:2}\\P{\\Q45;obliquing angle:45deg}\\P{\\W2;char width:2x}\\P{\\\\fArial;font:Arial}\\~{\\\\fTimes;font:Times}\\~{\\\\fCalibri;font:Calibri}\\P{\\Ooverline\\o}\\~{\\Lunderline\\l}"; _text = inputs->addStringValueInput(_commandId + "_text", "Text", txt); if (_text) _text->isVisible(false); _textSize = inputs->addValueInput(_commandId + "_textSize", "Size", "cm", ValueInput::createByReal(1)); if (_textSize) _textSize->isVisible(false); _textStyle = inputs->addButtonRowCommandInput(_commandId + "_textStyle", "Style", true); if (_textStyle) { Ptr items = _textStyle->listItems(); if (items) { items->add("Bold", false, "./resources/text_bold"); items->add("Italic", false, "./resources/text_italic"); items->add("UnderLine", false, "./resources/text_underline"); items->add("StrikeThrough", false, "./resources/text_strikethrough"); } _textStyle->isVisible(false); } _textFont = inputs->addStringValueInput(_commandId + "_textFont", "Font", "Arial"); if (_textFont) _textFont->isVisible(false); // transform for all custom graphics entity if (Ptr transformDistance = adsk::core::ValueInput::createByReal(0)) { _transform = inputs->addDistanceValueCommandInput(_commandId + "_transform", "Transform", transformDistance); if (_transform) { Ptr origin = adsk::core::Point3D::create(0, 0, 0); Ptr direction = adsk::core::Vector3D::create(1, 0, 0); if (origin && direction) { _transform->setManipulator(origin, direction); } } } // for custom graphics line style pattern _lineStylePattern = inputs->addDropDownCommandInput(_commandId + "_LSPattern", "Line Style Pattern", DropDownStyles::TextListDropDownStyle); if (_lineStylePattern) { Ptr listItems = _lineStylePattern->listItems(); if (listItems) { listItems->add(_solidLine_id, true); listItems->add(_centerLine_id, false); listItems->add(_dashedLine_id, false); listItems->add(_dotLine_id, false); listItems->add(_phantomLine_id, false); listItems->add(_tracksLine_id, false); listItems->add(_zigZagLine_id, false); } _lineStylePattern->isVisible(false); } // for line style weight _lineStyleWeight = inputs->addIntegerSliderCommandInput(_commandId + "_LSWeight", "Line Style Weight", 1, 20); _lineStyleWeight->valueOne(1); _lineStyleWeight->isVisible(false); // for line style scale _lineStyleScale = inputs->addIntegerSliderCommandInput(_commandId + "_LSScale", "Line Style Scale", 1, 100); _lineStyleScale->valueOne(10); _lineStyleScale->isVisible(false); // for view placement attribute _viewPlacementGroup = inputs->addGroupCommandInput(_commandId + "_VPGroup", "View Placement"); if (_viewPlacementGroup) { _viewPlacementGroup->isEnabledCheckBoxDisplayed(true); _viewPlacementGroup->isEnabledCheckBoxChecked(false); if (Ptr childInputs = _viewPlacementGroup->children()) { _viewCorner = childInputs->addButtonRowCommandInput(_commandId + "_viewCorner", "corner", false); if(_viewCorner) { if (Ptr listItems = _viewCorner->listItems()) { listItems->add("Upper Left", false, "./resources/upperLeft"); listItems->add("Upper Right", false, "./resources/upperRight"); listItems->add("Lower Left", false, "./resources/lowerLeft"); listItems->add("Lower Right", false, "./resources/lowerRight"); } } } } // for view scale attribute _viewScaleGroup = inputs->addGroupCommandInput(_commandId + "_VSGroup", "View Scale"); if (_viewScaleGroup) { _viewScaleGroup->isEnabledCheckBoxDisplayed(true); _viewScaleGroup->isEnabledCheckBoxChecked(false); if (Ptr childInputs = _viewScaleGroup->children()) { _pixelScale = childInputs->addFloatSliderCommandInput(_commandId + "_pixelScale", "pixel scale", "", 0.5,5,false); if (_pixelScale) { _pixelScale->valueOne(1); _pixelScale->setText("Smaller", "Larger"); } } } // for billboarding attribute _billboardingGroup = inputs->addGroupCommandInput(_commandId + "_BBGroup", "Billboarding"); if (_billboardingGroup) { _billboardingGroup->isEnabledCheckBoxDisplayed(true); _billboardingGroup->isEnabledCheckBoxChecked(false); if (Ptr childInputs = _billboardingGroup->children()) { _billboardingStyle = childInputs->addButtonRowCommandInput(_commandId + "_billboardingStyle", "style", false); if (_billboardingStyle) { if (Ptr listItems = _billboardingStyle->listItems()) { listItems->add("Screen", false, "./resources/One"); listItems->add("Axis", false, "./resources/Two"); listItems->add("Right Reading", false, "./resources/Three"); } } } } // } } } private: OnExecuteEventHandler onExecuteHandler_; OnDestroyEventHandler onDestroyHandler_; OnInputChangedEventHander onInputChangedHandler_; } cmdCreated_; extern "C" XI_EXPORT bool run(const char* context) { _app = Application::get(); if (!_app) return false; _ui = _app->userInterface(); if (!_ui) return false; Ptr doc = _app->activeDocument(); if (!doc) return false; Ptr prods = doc->products(); if (!prods) return false; Ptr prod = prods->itemByProductType("DesignProductType"); if (!prod) return false; _des = prod->cast(); if (!_des) return false; // get the entry for custom graphics Ptr activeProd = _app->activeProduct(); if (!activeProd) return false; Ptr cam = activeProd->cast(); if (cam) { _cgGroups = cam->customGraphicsGroups(); } else { Ptr rootComp = _des->rootComponent(); if (!rootComp) return false; _cgGroups = rootComp->customGraphicsGroups(); } if (!_cgGroups) return false; Ptr command = createCommandDefinition(); if (!command) return false; Ptr commandCreatedEvent = command->commandCreated(); if (!commandCreatedEvent) return false; commandCreatedEvent->add(&cmdCreated_); command->execute(); // prevent this module from being terminate when the script returns, because we are waiting for event handlers to fire adsk::autoTerminate(false); return true; } #ifdef XI_WIN #include BOOL APIENTRY DllMain(HMODULE hmodule, DWORD reason, LPVOID reserved) { switch (reason) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } #endif // XI_WIN