Overview

About CET

Some informational CET windows have been removed and consolidated into a new About CET window.

Canvas and Device

Canvas

Using GDI or integer-based method on the PdfCanvas is causing a lot of precision problems for PDFs and printing. To make PDF and printing more robust, the Canvas class will now be separated into two subclasses, ToPixelCanvas and VectorCanvas. In the future, PdfVectorCanvas will be used instead, and it subclasses from VectorCanvas where the methods will be floating-point based.

Device

The PixelDevice dc field on Canvas will be moved to ToPixelCanvas. Since VectorCanvas will not use GDI, it's device context or dc field will not be the PixelDevice type, but VectorDevice instead. The VectorDevice will support floating-point based methods instead.

Data Variables

The DRecord class now supports indexing into StrArray.

Snapper Graph Cache Debug Tool

Variants Constraints

The dsiConstraintsApplyStyle enumeration is not used anymore because we are limiting the constraint apply style options to only Top Down. As a result, all relevant interfaces in OFDAHeaderData will be deprecated and the ConstraintsApplyStyle tag will not be used.

cm.abstract

A bug would be triggered if an imageSnapper was placed in paperSpace and then stretched or scaled followed by an undo/redo operation. The same problem occured with all classes derived from drawRect if the layer was set to bottom. In order to remedy this issue the previously named photoSnapperUndoHook has been moved into the drawRect super class and renamed drawRectUndoHook.

COMaterials

COMaterials have been changed to always use GMaterial3D. Previously WrappedImageMaterial3D was used for texture materials and ColorMaterial3D for color materials.

cm.abstract.materialHandling

A few interfaces in the Material Handling Abstract related to the Animation Tool Spreading functionality has been reworked to be easier to use and customize.

  • MhSpreadPatternBehavior has been extended to allow for easier customization of snapper spreading cache keys. As a result, MhSpreadPatternBehavior and MhSpreadCacheKeyBehavior functionalities has been merged, with MhSpreadCacheKeyBehavior removed.
  • Some of the redundant SpreadPattern classes in the abstract has been removed, e.g. MhUnitLoadLevelSpreadPattern, MhUnitLoadNoSpreadPattern; along with the behaviors that existed solely to enable usage of these customized spread patterns.
  • MhSnapperSpreadVessel, MhSnapperRemoverVessel, MhSnapperSpreadToolAnimation, and MhSnapperInsertToolAnimation refactoring to consolidate spreading-related functionalities and various caching, with the introduction of a MhSpreadToolEnv structure.

cm.application

When copying papers within within a group, the copied paper would be assigned a new group instance, resulting in the paper ordering being incorrect. To solve this we now make sure the copied paper belongs to the same group as the original. We then rebuild the panel to update and get the correct paper ordering.

Additionally, when multiple papers within a group where copied one of the papers would have an additional copy made. This has been fixed by making sure the specific paper is only copied once.

cm.core

Previously when changing any of the pageSetup settings in paperSpace (such as paper resolution, margins or paper dimensions) and creating a new drawing, the settings were reset to their default values. Changes have now been made to reflect the most recent change made to a paper. A new drawing will thus have the same settings as the last paper created.

cm.core.xclip

When moving the 2D view rectangle in paperspace users would experience significant lag due to a costly rebuild2D invalidation call each frame. This lag is mitigated by instead running the rebuild in the snappers' updateContent method.

cm.std.photo

PhotoSnapper now shows unrendered photos in the photo series. Double clicking a PhotoSnapper now opens a SelectPhotoDialog.

cm.track.probe

Rewrite of probes.

  • Probe syntax have less overhead while probes are disabled.
  • Opened up the interface to allow utils outside of probes package.
  • Started work on probe utilities under cm.track.probe.util though that work is still WIP.
Public classes:
Probe - Single probe.
Probes - Collection of all probes.
ProbeTest - Single probe test.
ProbeTests - All probe tests for a single probe.
ProbeTestResult - Calculates median, avg, min, max etc for a ProbeTests.

cm.track.probe.util

Contains functionallity to:

  • Monitor probes in real time. 'monitor.cm'
  • Diff/Compare probe results. 'diff.cm'
  • Save probe tests and diff results. 'stream.cm'

Compile Time Changes

About CET

The following classes and functions have been removed:

cm.core.technologyPartners:

Removed: public void showTechnologyPartners(Window parent, str key=null);

cm.core.legacy.oldAboutDialog:

Removed: public class OldAboutDialog;
Removed: public OldAboutDialog showOldAboutDialog(Window parent);

cm.core.ui.aboutDialog:

Removed: public class AboutDialog;
Removed: public void showAboutDialog(Window parent, str key=null);

cm.core.ui.cetAboutDialog:

Removed: public class CetAboutDialog;
Removed: public CetAboutDialog showCetAboutDialog(Window parent);

cm.win.technologyPartnersDialog:

Removed: public class TechnologyPartnersDialog;
Removed: public TechnologyPartnersDialog showTechnologyPartnersDialog(Window parent);

The following classes have their parent class changed:

cm.abstract.consumer.ConsumerAboutDialog: AboutDialog -> DialogWindow
cm.abstract.consumerG2.ConsumerAboutDialog: AboutDialog -> DialogWindow

To show the new About CET dialog, call cm.core.ui.showAboutCet(Window parent)

Canvas and Device

// cm/core/graph/gAdvImage.cm, Class: GAdvImage
Old: final public mrgn combinedClipRgn(Canvas gd, mrgn oldRgn)
New: final public mrgn combinedClipRgn(ToPixelCanvas gd, mrgn oldRgn)

// cm/core/windowView.cm, Class: WindowView
Old: public Canvas canvas
New: public ToPixelCanvas canvas

// cm/draw/canvas.cm, Class Canvas
Old: public constructor(PixelDevice c)
New: public constructor()
Removed: public PixelDevice dc

// cm/draw/canvas.cm, new global function to make things compile easily rather than casting the Canvas to ToPixelCanvas
New: public PixelDevice getCanvasDC(Canvas c)

// cm/draw/gdiCanvas.cm
Old: public class GdiCanvas extends Canvas
New: public class GdiCanvas extends ToPixelCanvas

// cm/std/print/photoLayoutSnapshot.cm, Class PhotoLayoutSnapshot
Old: extend public void draw(Canvas canvas, rectI targetRect) : abstract
New: extend public void draw(ToPixelCanvas canvas, rectI targetRect) : abstract

// cm/std/print/photoLayoutSnapshot.cm, Class PhotoLayoutREDSnapshot
Old: public void draw(Canvas canvas, rectI targetRect)
New: public void draw(ToPixelCanvas canvas, rectI targetRect)

CollabG3 (CollabPro)

core.collabG3

CollAccountType and all related classes are undeprecated to be used for holding subscription tier information.

# collAccountTypes.cm
Old: public class CollAccountTypes : deprecated
New: public class CollAccountTypes

Old: public class CollAccountType : deprecated, abstract
New: public class CollAccountType : abstract

Old: public class CollAccountTypeFree extends CollAccountType : deprecated
New: public class CollAccountTypeFree extends CollAccountType

Old: public class CollAccountTypeCorporate extends CollAccountType : deprecated
New: public class CollAccountTypeCorporate extends CollAccountType

Old: public class CollAccountTypeAdvanced extends CollAccountType : deprecated
New: public class CollAccountTypeAdvanced extends CollAccountType


# collProjectController.cm
Old: public str accountTypeKey : deprecated
New: public str accountTypeKey

The following accessors/mutators related to CollFileG3 are removed in favour of using a static type key to access files.

# collCollection.cm
Removed: extend public CollFileG3{} serverFiles(CollFileType type)
Removed: extend public symbol{} serverFileIds(CollFileType type)
Removed: extend public CollFileG3{} editFiles(CollFileType type)
Removed: extend public symbol{} loadedFileIds(CollFileType type)
Removed: extend public CollFileG3{} loadedFiles(CollFileType type)


# collFile.cm
Removed: extend public CollFileG3{} files(CollFileType t)
Removed: extend public symbol{} ids(CollFileType t)
Removed: extend public void changeType(CollFileType t)


# collFileSubModel.cm
Old: extend public CollFileG3{} loadedFiles(CollFileType type)
New: extend public CollFileG3{} loadedFiles(str typeKey)


# collFileType.cm
Old: final public str packageName()
New: final public symbol packageName()

Old: final public str packageVersion()
New: final public version packageVersion()

CollFileG3 and CollUFOFileType constructors are modified to take in a CollFileTypeId parameter.

# collFile.cm
Old: public constructor(CollFileType type, str name, int v, symbol id)
New: package constructor(CollFileTypeId typeId, str name, int v, symbol id)


# collUFOFileType.cm
Removed: public constructor()

Old: public constructor(str id, str description)
New: public constructor(CollFileTypeId srcTypeId)

The following file type classes are removed.

Removed: public class CollPdfFileType extends CollDocFileType
Removed: public class CollDwgFileType extends CollDocFileType

The signatures of the following utility functions are modified:

# collFileNamer.cm
Old: public str getUniqueCopiedName(CollCollectionG3 this, str fileName, CollFileType fileType, collCopyMode mode=collCopyMode.normal)
New: public str getUniqueCopiedName(CollCollectionG3 this, str fileName, str fileTypeKey=null, collCopyMode mode=collCopyMode.normal)

Old: public str getUniqueNewName(CollCollectionG3 this, str rootName, CollFileType fileType)
New: public str getUniqueNewName(CollCollectionG3 this, str rootName, str fileTypeKey)

Old: public bool isUniqueFileName(CollCollectionG3 this, str name, CollFileType fileType=null)
New: public bool isUniqueFileName(CollCollectionG3 this, str name, str fileTypeKey=null)

Old: public bool isUniqueServerFileName(CollCollectionG3 this, str name, CollFileType fileType=null)
New: public bool isUniqueServerFileName(CollCollectionG3 this, str name, str fileTypeKey=null)

Old: public bool isUniqueLocalFileName(CollCollectionG3 this, str name, CollFileType fileType=null)
New: public bool isUniqueLocalFileName(CollCollectionG3 this, str name, str fileTypeKey=null)


# collFileType.cm
Old: public void unregister(CollFileType type)
New: public void unregisterCollFileType(str key)

Old: public CollFileType collFileType(str id)
New: public CollFileType resolveCollFileType(CollFileTypeId typeId, collReleaseStage stage)


# collUFOFileType.cm
Old: public CollFileType collUFOFileType()
New: public CollFileType collUFOFileType(CollFileTypeId typeId)

Compiler

if-as statement and expression cleanup

In 13.5, the if-as statement and if-as expression were quite "magical", able to apply a wide variety of conversions including function calls and constructors. This can create confusing and error-prone situations.

In 14.0, the if-as statement is limited to membership testing and unboxing conversions (see below). The if-as expression is now exactly equivalent in behaviour to the if-as statement.

Example A

public void foo(Object o) {
    // These two are equivalent
    if (o as Str) {pln(o.v);}
    if (o as str) {pln(o);}

    // These two are equivalent
    if (o as Int) {pln(o.v);}
    if (o as int) {pln(o);}   // new in 14.0

    // These two are equivalent in 14.0
    if (o as int) {pln(o);} else {pln("not an int");}
    pln(o as int ? o : "not an int");
}

Example B

public class A {
    public constructor() {pln(this, " is created");}
}

public class B {
    public constructor(A a) {pln(this, " is created from A");}
}

public class C extends A {
    public constructor() {}
    public constructor(A a) {pln(this, " is created from A");}
}

public void foo(A a) {
    pln("a=", a);
    if (a as B) {pln("a as B=", a);} // forbidden in 14.0
    if (a as C) {pln("a as C=", a);}
}
{
    foo(A());
    pln();
    foo(C());
}

Since B does not inherit from A, if (a as B) is not valid in 14.0. It only works in 13.5 because there is a constructor which "converts" A into a new instance of B.

This happened in practice with DialogWindow and Button, respectively, since Button has a constructor with one required argument of type Window (and DialogWindow is a Window).

Output in 13.5

A(175) is created
a=A(175)
B(165) is created from A
a as B=B(165)

C(171) is created
a=C(171)
B(161) is created from A
a as B=B(161)
a as C=C(171)

Output in 14.0

A(36) is created
a=A(36)

C(79) is created
a=C(79)
a as C=C(79)

Dynamic compilation improvements (cm.runtime.compileFun)

The compileFun CM function has been replaced with a native implementation, which is faster and cleaner. The remove optional argument has been removed as the new version avoids writing the code to disk in any case.

Old: public Function compileFun(str def, bool output=false, bool remove=true)
New: public Function compileFun(str def, bool output=false)

Old: public Function compileFun(StrBuf def, bool output=false, bool remove=true)
New: public Function compileFun(StrBuf def, bool output=false)

A similar function which returns all compiled functions in the file, rather than just the first one, has been added.

Added: public Function[] compileFuns(str def, bool output=false)
Added: public Function[] compileFuns(StrBuf def, bool output=false)

Type conversion search correctness and optimization

The internal code responsible for finding the appropriate conversion path between types (if any) has been significantly improved. There is a small risk of surprising behaviour since the new algorithm performs an exhaustive search and selects the "best" path, rather than using flawed pruning heuristics.

In some circumstances, the type conversion search may recurse forever; the old version would treat this as a failure to find an appropriate conversion, the new version will treat this as an error.

Save/load robustness improvements

Old: public bool cm.io.easySave(Object obj, Url url, bool pkgVersions=true, bool fast=false);
New: public bool cm.io.easySave(Object obj, Url url, bool pkgVersions=true, bool fast=false, bool verifyCRC=false);

Old: public bool cm.io.object.safeReplaceUrl(Url this, Url target, bool xtrace=false)
New: public bool cm.io.object.safeReplaceUrl(Url this, Url target, bool verifyCRC=false, bool xtrace=false)

Implicit-this for functions taking unqualified value types

public void foo(FooClass this) {
    pln(field); // equivalent to this.field
}
public void foo(fooValue& this) {
    pln(field); // equivalent to this.field
}
public void foo(fooValue this) {
    pln(field); // equivalent to this.field in 14.0
}

Garbage collector interface

The garbage collector (GC) has two different pause-states; "frozen" and "parked". The former prevents almost all GC activity, the latter forces the GC to finish any pending work and prevents all GC activity. The GC interface now exposes gcUnPark so that CM code can enter and leave the "parked" state.

Added: gcUnPark();

DLL interface changes

14.0 makes many changes to the CM-DLL interface, you must rebuild all DLLs.

The CM-DLL interface now uses a secondary version check, allowing breaking API changes without necessarily changing the size of the DllStartInfo struct.

Due to internal refactoring, funFunLinkOffset has been removed; use getFunLink(Fun*) instead.

Removed: int funFunLinkOffset;

Default C++ compilation flags changes

We have enabled MSVC errors for comparisons between signed and unsigned values. If you encounter code which you cannot migrate for this (e.g. third-party libraries), add the following lines to your DLL's Makefile to disable the errors.

CFLAGS := $(filter-out /w34287,$(CFLAGS))
CFLAGS := $(filter-out /w34388,$(CFLAGS))

HighlightSnapper

Deprecated: cm.core.ui.HighlightSnapper

The HighlightSnapper class used for InvalidListDialog have been deprecated and replaced with the more modern implementation of HighlightVessels, to resolve some issues with using Snapper for temporary graphics. Consider replacing any relevant usage with highlightInvalidObject(), or related methods in cm/core/highlightVessel.cm.

As a consequence, these fields and references to them have also been removed:

Removed: InvalidListDialog::HighlightSnapper{} hlSnappers
Removed: DsIncompleteOptionDialog::HighlightSnapper{} hlSnappers
Removed: DsCatalogVersionDialog::HighlightSnapper{} hlSnappers

Variants Constraints

custom.dataCatalog.builder.constraints

DcDBBuilderEditConstraintsCard

Removed the entire Constraints Toolbox for the following reasons:

  1. Constraints apply style is fixed to Top Down and All is now deprecated.
  2. Allow individual toggling of constraint expressions to be a valid/invalid constraint type instead of forcing all expressions to abide to a single type.
Removed: public DcDBBuilderShrinkWindow toolboxWindow;
Removed: public Display appleStyleDisplay;
Removed: public DsRadioButton applyStyleAllRadioButton;
Removed: public DsRadioButton applyStyleTopDownRadioButton;
Removed: public StateControlGroup applyStyleControlGroup;
Removed: public Display constraintTypeDisplay;
Removed: public DsRadioButton validConstraintTypeRadioButton;
Removed: public DsRadioButton invalidConstraintTypeRadioButton;
Removed: public StateControlGroup constraintTypeControlGroup;

New argument to determine the constraint's expression type.

Old: extend public bool validExpression(str exp, StrBuf error)
New: extend public bool validExpression(dsiConstraintExpressionType constraintExpType, str exp, StrBuf error)

DcConstraintExpColumn

Column label does not need to be updated dynamically anymore.

Removed: public str labelText()

custom.dataCatalog.builder.undo

dcConstraintsUndoOp.cm is removed as dsiConstraintsApplyStyle and dsiConstraintType enumerations are not used anymore.

Removed: public class DcConstraintTypeUndoOp extends DcUndoOp

cm.abstract.dataSymInterface

The following method signatures are changed to accommodate the addition of the constraint expression type.

// DsiExprValidationEnv (dsiExprValidationEnv.cm)
Old: public constructor(VxRuntime rt, str expr, DataCatalog cat)
New: public constructor(VxRuntime rt, dsiConstraintExpressionType exprType, str expr, DataCatalog cat)

Old: extend public void doesNothign(VxExpr e, StrBuf error)
New: extend public void doesNothing(VxExpr e, StrBuf error)

// dsiVariants.cm
Old: public VConstraint dsiCreateConstraint(DataCatalog catalog, str expression)
New: public VConstraint dsiCreateConstraint(dsiConstraintExpressionType expressionType, str expression)

Old: public bool dsiValidateConstraintExpr(DataCatalog cat, str exp, StrBuf error=null)
New: public bool dsiValidateConstraintExpr(DataCatalog cat, dsiConstraintExpressionType exprType, str expr, StrBuf error=null)

Old: public str->SFeature dsiVariantsFeatures(DsiPData data, str featureCode)
New: public str->SFeature dsiVariantsFeatures(DsiPData data, str featurePath)

Old: public str->Object dsiVariantsTableSelectedValues(DsiPData data, str featCode)
New: public str->Object dsiVariantsTableSelectedValues(DsiPData data, str featurePath)

Removed: public void dsiClearVariantsTableCache()

All interfaces of constraintsApplyStyle and constraintType in OFDAHeaderData are now deprecated.

// OFDAHeaderData
Deprecated: private dsiConstraintsApplyStyle _constraintsApplyStyle : deprecated;
Deprecated: extend public dsiConstraintsApplyStyle constraintsApplyStyle() : deprecated
Deprecated: extend public dsiConstraintsApplyStyle constraintsApplyStyle=(dsiConstraintsApplyStyle constraintsApplyStyle) : deprecated
Deprecated: extend public dsiConstraintType constraintType() : deprecated
Deprecated: extend public dsiConstraintType constraintType=(dsiConstraintType constraintType) : deprecated

cm.abstract

AccessoryLocation

Commit ae48deba Removed the acceptAccessory() method in favor of the acceptLocation() method on AccessoryEnv.

cm.abstract.dataSymbol

DsControlPanelPage

The visibility of DsControlPanelPage is no longer affected by whether the Catalog Browser is turned on or not. It will be always visible in control panel. The "Package required" and "Extensions" under Portfolio Info in "Catalogue Details" dialog will now show the target extensions of the portfolio if any.

A few methods that responsible to check for "Catalog Details" visibility has been removed in 14.0.

// class DsControlPanelPage 
Removed: final public bool isCtlgBrowserTurnedOn()
Removed: extend public void setCatDetailsVisibility(bool visible)

Removed: public void dsEnableCatDetails(bool enable)

Methods changed in class DsCatInfoView

Embedded extension's 'getCatEmbeddedExtensions' method has been renamed to license for clarity.

// class DsCatInfoView
Old: extend public str getCatEmbeddedExtensions(str[] embedded)
New: extend public str getCatRequiredLicenses(DsCatCatalogue cat)

// class DsCatInfoView
Old: extend public str getCatEmbeddedExtensionNames(str[] pkgs)
New: extend public str getCatEmbeddedExtensionNames(DsCatCatalogue cat)

Creator item drag animation

Introduced a new class DsToolboxCreatorDragAnimation that responsible dragged item removal. With this new added class, all item's drag animation inheritance has been updated accordingly.

New: public class DsToolboxCreatorDragAnimation extends DsDragAnimation

New: public class DsToolboxCreatorThumbnailViewMoveDragAnimation extends DsThumbnailViewMoveDragAnimation 

Old: public class DsToolboxCreatorFillerInsertDragAnimation extends DsThumbnailViewMoveDragAnimation
New: public class DsToolboxCreatorFillerInsertDragAnimation extends DsToolboxCreatorThumbnailViewMoveDragAnimation

Old: public class DsToolboxCreatorSchemeButtonInsertDragAnimation extends DsDragAnimation
New: public class DsToolboxCreatorSchemeButtonInsertDragAnimation extends DsToolboxCreatorDragAnimation

Old: public class DsToolboxCreatorGroupInsertDragAnimation extends DsDragAnimation
New: public class DsToolboxCreatorGroupInsertDragAnimation extends DsToolboxCreatorDragAnimation

Old: public class DsToolboxCreatorImageSectionInsertDragAnimation extends DsDragAnimation
New: public class DsToolboxCreatorImageSectionInsertDragAnimation extends DsToolboxCreatorDragAnimation

cm.abstract.interop

The following Excel-related classes in cm.abstact.interop.excelObj.cm are now deprecated, as there are identical classes in cm.core.msOffice.excel with more functionalities.

// cm.abstract.interop.excelObj.cm
Deprecated: public class ExcelObj extends NetObj : deprecated
Deprecated: public class ExcelWorkbook extends NetObj : deprecated
Deprecated: public class ExcelSheet extends NetObj : deprecated
Deprecated: public class ExcelRange extends NetObj : deprecated

cm.abstract.k2

K2Creator changes

Data catalogue behaviors (K2XpToDataControllerBehavior) will now use the 'Code' field from Smart Objects (XpSnapperSpawner) as part no. The Part No field on XpDataBehavior is no longer used, but remains to make the transition easier.

cm/abstract/k2/assortment.cm

Removed: K2Assortment::public K2StyleStore styleStore

cm/abstract/k2/k2CatalogAccess.cm

Old: extend public K2PropDef propDef(XpPropDef def) {
New: extend public K2PropDef propDef(XpPropDef def, XpShape shape) {

cm/abstract/k2/k2Property.cm

Old: public constructor(XpPropDef xpPropDef) {
New: public constructor(XpPropDef xpPropDef, XpShape shape) {

cm/abstract/k2/k2StyleStore.cm

Removed: public class K2StyleStore

cm/abstract/k2/xpDefinitions.cm

Old: public Class{} allNonAbstractSubclasses(Class definition) {
New: private Class{} allNonAbstractSubclasses(Class definition) {

Removed: public Class[] runtimeGetAllXpDefinitions() {
Removed: public void checkXpDefinitions() { }

cm/abstract/k2/k2SnapperSpawner.cm

Old: public class K2SnapperSpawner extends SnapperSpawner : inherit constructors {
New: public class K2SnapperSpawner extends SnapperSpawner : abstract, inherit constructors {

cm/abstract/k2/xpToK2.cm

Removed: public K2PropDef toK2PropDef(XpPropDef xpPropDef, K2Assortment assortment=null) {

Old: public PropDef toK2(XpPropDef xpPropDef, K2Assortment assortment=null) {
New: public PropDef toK2(XpPropDef xpPropDef, XpShape shape, K2Assortment assortment=null) {

Old: public PropInputSetting toK2(XpPropInputSetting xpPropInputSetting, XpPropDef xpPropDef, str label=null) {
New: public PropInputSetting toK2(XpPropInputSetting xpPropInputSetting, XpPropDef xpPropDef, XpShape shape, str label=null) {

Removed: public Object k2Default(XpPropDef xpPropDef) {

cm/abstract/k2/behavior/k2BehaviorStreamRenamer.cm

Old: extend public K2Behavior process(K2Behavior unstreamed, K2Assortment assortment) {
New: extend public K2Behavior[] process(K2Behavior unstreamed, K2Assortment assortment) {

cm/abstract/k2/behavior/k2ShapeInvalidationEnv.cm

Old: public class K2ShapeInvalidationEnv extends K2InvalidationEnv {
New: package class K2ShapeInvalidationEnv extends K2InvalidationEnv {

cm/abstract/k2/data/k2DataCatalogAccess.cm

Old: public K2PropDef propDef(XpPropDef def) {
New: public K2PropDef propDef(XpPropDef def, XpShape shape) {

cm/abstract/k2/engine/k2AlternativeFunctions.cm

Old: public XpShape[] findAlternatives(K2AlternativeEngine this, Line mouseLine=null, Point2D p=null, Space space=null) {
New: public XpShape[] findAlternatives(K2AlternativeEngine this, Snapper existing, Line mouseLine=null, Point2D p=null, Space space=null) {

cm/abstract/k2/face/xpFaceToFaceFilter.cm

Removed: XpFaceIntersectFilter::public bool excludeEdges

cm/abstract/k2/face/xpGeometricFaceOps.cm

Old: K2ExcludeNotInCornerToCornerFaceOp::public LayerExpr corner0
New: K2ExcludeNotInCornerToCornerFaceOp::public LayerExpr corner0LayerExpr

Old: K2ExcludeNotInCornerToCornerFaceOp::public LayerExpr corner1
New: K2ExcludeNotInCornerToCornerFaceOp::public LayerExpr corner1LayerExpr

Old: K2ExcludeNotInCornerToCornerFaceOp::constructor(LayerExpr corner0=null, LayerExpr corner1=null)
New: K2ExcludeNotInCornerToCornerFaceOp::constructor(LayerExpr corner0LayerExpr, LayerExpr corner1LayerExpr)

cm/abstract/k2/library/k2Library.cm

Removed: K2Library::extend public str splitStr(str s, int length) {

Old: public constructor(LayerExpr expr=null, str sortKey=null, function() viewModeHook=function k2SetDefaultViewModes) {
New: public constructor(LayerExpr expr=null, str sortKey=null, function() viewModeHook=function k2SetDefaultViewModes, int maxVisibleSpawners=20) {

cm/abstract/k2/library/k2GeneralLibrary.cm

Removed: K2GeneralLibrary::extend public void addProjectInfoLimb(LibraryLimb parent) {

cm/abstract/k2/library/k2InsertNodeChooser.cm

Removed: K2InsertNodeChooser::public K2InsertNodeFinder finder

cm/abstract/k2/library/k2InsertNodeFinder.cm

Removed: public class K2InsertNodeFinder

cm/abstract/k2/worktop/k2WorktopCandidateFaces.cm

Old: public XpFace[] worktopCandidateFacesToShapeAlternativeFaces(XpFace[] candidates, LayerExpr faceFilter, WindowView view) {
New: public XpFace[] buildWorktopCandidateFaces(XpFace[] faces, LayerExpr candidateTag, WindowView view) {

Old: public void bridgeWorktopCandidateFaces(XpFace[] candidates) {
New: private void bridgeWorktopFaces(XpFace[] candidates) {

Old: public void adaptAdaptableWorktopFaces(XpFace[] faces) {
New: private void adaptAdaptableWorktopFaces(XpFace[] faces) {

cm/abstract/k2/worktop/k2SoffitCandidateFaces.cm

Old: public XpFace[] soffitCandidateFacesToShapeAlternativeFaces(XpFace[] candidates, LayerExpr faceFilter, WindowView view) {
New: package XpFace[] buildSoffitCandidateFaces(XpFace[] faces, LayerExpr faceFilter, WindowView view) {

cm/abstract/k2/worktop/k2WorktopAlternatives.cm

Old: public XpWorktopShape k2DefaultWorktopShapeAlternative(XpFace[] candidateFaces, XpFace[] joints, Line mouseLine=null, Point2D p=null, double z=0, LayerExpr layer=null) {
New: package XpWorktopShape defaultWorktopAlternative(WorktopAlternativeEnv env) {

Old: public XpWorktopShape k2ExtendBackWorktopShapeAlternative(XpFace[] candidateFaces, XpFace[] joints, Line mouseLine=null, Point2D p=null, double z=0, LayerExpr layer=null) {
New: package XpWorktopShape extendBackWorktopAlternative(WorktopAlternativeEnv env) {

Old: public XpWorktopShape k2ExtendOverlappingBackWorktopShapeAlternative(XpFace[] candidateFaces, XpFace[] joints, Line mouseLine=null, Point2D p=null, double z=0, LayerExpr layer=null) {
New: package XpWorktopShape extendOverlappingBackWorktopAlternative(WorktopAlternativeEnv env) {

Old: public XpWorktopShape k2MergedAndJoinedWorktopShapeAlternative(XpFace[] candidateFaces, XpFace[] joints, Line mouseLine=null, Point2D p=null, double z=0, LayerExpr layer=null) {
New: package XpWorktopShape mergedAndJoinedWorktopAlternative(WorktopAlternativeEnv env) {

Old: public XpWorktopShape k2ExtendSideWorktopShapeAlternative(XpFace[] candidateFaces, XpFace[] joints, Line mouseLine=null, Point2D p=null, double z=0, LayerExpr layer=null) {
New: package XpWorktopShape extendSideWorktopAlternative(WorktopAlternativeEnv env) {

Old: public XpWorktopShape createWorktopShapeAlternativeWithJoints(XpFace[] faces, Line mouseLine=null, Point2D p=null, double z=0, XpFace[] joints=null) {
New: public XpWorktopShape createWorktopShapeAlternativeWithJoints(WorktopAlternativeEnv env, XpFace[] faces) {

cm/abstract/k2/worktop/k2WorktopLayout.cm

Removed: extend public double frontOverhang() {
Removed: extend public double sideOverhang() {
Replaced with K2WorktopOverhangModifier (behavior).

cm/abstract/k2/worktop/k2WorktopModifierBehavior.cm

Old: extend public void modifyFaces(K2Snapper owner, XpFace[] faces) {
New: extend public void modifyFaces(K2Snapper owner, XpFace[] faces, WindowView view) {

cm/abstract/k2/worktop/worktopFeatureFaces.cm

Old: public XpFace[] k2GenericSnapperShapeWorktopFaces(K2Snapper snapper, symbol engineTag, double z, double h, double overhang) {
New: package XpFace[] k2GenericSnapperShapeWorktopFaces(K2Snapper snapper, symbol engineTag, double z, double h) {

Old: public XpFace[] k2AdaptableFrontGapWorktopFaces(K2Snapper snapper, symbol engineTag, double z, double h, double overhang) {
New: package XpFace[] k2AdaptableFrontGapWorktopFaces(K2Snapper snapper, symbol engineTag, double z, double h) {

Old: public XpFace[] k2AdaptableFrontAndSideWorktopFaces(K2Snapper snapper, symbol engineTag, double z, double h, double overhang) {
New: package XpFace[] k2AdaptableFrontAndSideWorktopFaces(K2Snapper snapper, symbol engineTag, double z, double h) {

cm/abstract/k2/worktop/k2BacksplashCutoutsEngine.cm

Old: public class K2GenericInvalidateFun extends K2EngineInvalidateFun {
New: private class K2GenericInvalidateFun extends K2EngineInvalidateFun {

Old: public class K2AppendArchitecturalCutoutsFun extends K2EngineFun {
New: private class K2AppendArchitecturalCutoutsFun extends K2EngineFun {

cm/abstract/k2/xp/xpAnglePropDef.cm

Old: public Object default() {
New: public Object default(XpShape shape) {

Old: public XpDomain domain() {
New: public XpDomain domain(XpShape shape) {

cm/abstract/k2/xp/xpBehaviorPropDef.cm

Old: public Object default() {
New: public Object default(XpShape shape) {

Old: public XpDomain domain() {
New: public XpDomain domain(XpShape shape) {

cm/abstract/k2/xp/xpBool.cm

Old: extend public SubSet subset() {
New: extend public SubSet subset(XpShape shape) {

Old: public SubSet subset() {
New: public SubSet subset(XpShape shape) {

cm/abstract/k2/xp/xpBoolPropDef.cm

Old: public Object default() {
New: public Object default(XpShape shape) {

Old: public XpDomain domain() {
New: public XpDomain domain(XpShape shape) {

cm/abstract/k2/xp/xpBoolSelector.cm

Old: public Object default() {
New: public Object default(XpShape shape) {

cm/abstract/k2/xp/xpDataMaterialPropDef.cm

Old: public Object default() {
New: public Object default(XpShape shape) {

cm/abstract/k2/xp/xpFace.cm

XpFace now now supports bent faces, i.e a face is described by an arc rather than a line. The bend of the face is controlled by the relativeBendTangentAngle member.

Most things should work the same way for straight faces (whether a face is straight can be checked with isStraight()), but you must be mindful that a face now describes an arc when you use it. For example, a point between p0 and p1 might not be on the face, if it isn't straight.

Because of this, some of its methods has changed name and/or behavior.

Old: final public point center()

// midPoint describes the center between p0 and p1, i.e the old center() if you ignore the bend of the face.
// The midPoint isn't necessarily located on the face.
New: final public point midPoint()

// bendZenith describes the center of the arc of the face.
// For straight faces, this is the same as midPoint().
New: final public point2D bendZenith()
Old: final public double length()

// The actual length of the worktop, considering the bend.
// Always greater than or equal to the old length().
// Equals the old length() for straight faces.
New: final public double length()

// The length of the straight line from p0 to p1
// Same as the old implementation of length().
// Equals the new length() as well as the old for straight faces.
New: final public double backLength() 
Old: final public bool contains(point2D& p, double precision=1e-6)

// The new implementation ignores the bend of the line. It works exactly the same as before.
// Might not be what you want.
New: final public bool straightContains(point2D& p, double precision=1e-6)

// Returns the distance between a point and the face, including bend.
New: final public double distance(point2D p)
Old: final public rect bound()
New: final public box  bound(double thickness=0)
New: final public rect bound2D(double thickness=0)

cm/abstract/k2/xp/xpFaceShapeDef.cm

Old: public constructor(XpFace face) {
New: public constructor(XpFace face, XpMeasureBasePropDef def) {

cm/abstract/k2/xp/xpFeaturePropDef.cm

Old: public Object inputAttributes() {
New: public Object inputAttributes(XpShape shape) {

cm/abstract/k2/xp/xpGenerateStrPropDef.cm

Old: public Object default() {
New: public Object default(XpShape shape) {

cm/abstract/k2/xp/xpLayoutPropDef.cm

Old: public Object default() {
New: public Object default(XpShape shape) {

Old: public XpDomain domain() {
New: public XpDomain domain(XpShape shape) {

cm/abstract/k2/xp/xpMaterialPropDef.cm

Old: public Object inputAttributes() {
New: public Object inputAttributes(XpShape shape) {

Old: public Object default() {
New: public Object default(XpShape shape) {

Old: public XpDomain domain() {
New: public XpDomain domain(XpShape shape) {

cm/abstract/k2/xp/xpMeasure.cm

Old: extend public Object default() {
New: extend public Object default(XpShape shape) {

Old: extend public SubSet subset() {
New: extend public SubSet subset(XpShape shape) {

Old: public Object default() {
New: public Object default(XpShape shape) {

Old: public SubSet subset() {
New: public SubSet subset(XpShape shape) {

Old: public constructor() {
New: public constructor(XpMeasureBasePropDef def) {

cm/abstract/k2/xp/xpMeasurePropDef.cm

Old: public str->Object inputArgs() {
New: public str->Object inputArgs(XpShape shape) {

Old: public Object default() {
New: public Object default(XpShape shape) {

Old: public SubSet domain() {
New: public SubSet domain(XpShape shape) {

Old: public class XpMeasurePropDef extends XpPropDef {
New: public class XpMeasurePropDef extends XpMeasureBasePropDef {

cm/abstract/k2/xp/xpPanelShapeDef.cm

Old: public XpPropInputSetting propInputSetting(str key) {
New: public XpPropInputSetting propInputSetting(str key, XpShape shape) {

cm/abstract/k2/xp/xpPropDef.cm

Old: extend public Object inputAttributes() {
New: extendpublic Object inputAttributes(XpShape shape) {

Old: extend public str->Object inputArgs() {
New: extend public str->Object inputArgs(XpShape shape) {

Old: extend public Object default() {
New: extend public Object default(XpShape shape) {

Old: extend public XpDomain domain() {
New: extend public XpDomain domain(XpShape shape) {

Old: extend public SubSet subset() {
New: extend public SubSet subset(XpShape shape) {

cm/abstract/k2/xp/xpPropDefArgs.cm

Old: extend public str->Object args(XpPropDef def) : abstract { }
New: extend public str->Object args(XpPropDef def, XpShape shape) : abstract { }

Old: public str->Object args(XpPropDef def) {
New: public str->Object args(XpPropDef def, XpShape shape) {

cm/abstract/k2/xp/xpRsStr.cm

Removed: public class XpParentRsStr

cm/abstract/k2/xp/xpShapeDef.cm

Old: extend public XpPropInputSetting propInputSetting(str key) {
New: extend public XpPropInputSetting propInputSetting(str key, XpShape shape) {

cm/abstract/k2/xp/xpSnapperSpawnerPropDef.cm

Old: public Object default() {
New: public Object default(XpShape shape) {

Old: public SubSet domain() {
New: public SubSet domain(XpShape shape) {

cm/abstract/k2/xp/xpSplitPanelShapeDef.cm

Old: public XpPropInputSetting propInputSetting(str key) {
New: public XpPropInputSetting propInputSetting(str key, XpShape shape) {

cm/abstract/k2/xp/xpStylePropDef.cm

Old: public Object default() {
New: public Object default(XpShape shape) {

Old: public SubSet domain() {
New: public SubSet domain(XpShape shape) {

cm/abstract/k2/xp/xpStyleSelector.cm

Old: public Object default() {
New: public Object default(XpShape shape) {

cm/abstract/k2/xp/xpUserStrPropDef.cm

Old: public Object default() {
New: public Object default(XpShape shape) {

Old: public SubSet domain() {
New: public SubSet domain(XpShape shape) {

cm/abstract/k2/xp/xpWorktopLayout.cm

Removed: XpWorktopLayout::public double frontOverhang
Removed: XpWorktopLayout::public double sideOverhang

cm.abstract.materialHandling

Changes to after engine initial export behavior

MhAfterEngineInitialExportBehavior interface changes:

    Old : extend public void afterInitialExport(MhSnapper parent, MhSnapper owner) {}
    New : extend public void afterInitialExport(MhSystemCollection system, MhSnapper parent, MhSnapper owner) {}

MhAfterEngineInitialExportBehavior::void afterInitialExport(MhSystemCollection system) now has a default implementation, moved from MhRowAfterEngineInitialExportBehavior.

    extend public void afterInitialExport(MhSystemCollection system) {
        Snapper[] sortedSnappers = sortedSystemSnappers(system);

        for (MhSnapper snapper in sortedSnappers) {
            if (!system.exportedFromEngine(snapper)) continue;

            ?MhSnapper parent = snapper.parent;
            forAllBehaviors (b in snapper) {
            if (b as MhAfterEngineInitialExportBehavior) {
                b.afterInitialExport(system, parent, snapper);
            }
        }

            snapper.validateBehaviors(sAfterInitialExport);
        }
    }

MhCheckValidFrameChildBehavior now extends from MhAfterEngineInitialExportBehavior.

    Old : public class MhCheckValidFrameChildBehavior extends MhBehavior
    New : public class MhCheckValidFrameChildBehavior extends MhAfterEngineInitialExportBehavior

MhCheckValidFrameChildBehavior interface changes:

    Old : extend public bool isInvalidFrameChild(MhSnapper parent, MhSnapper child) {
    New : extend public bool isInvalidFrameChild(MhSnapper parent, MhSnapper child, MhEngine engine=null) {

    Old : extend public void removeInvalidChild(MhSnapper parent, MhSnapper child) {
    New : extend public void removeInvalidChild(MhSnapper parent, MhSnapper child, MhEngine engine=null) {

MhCheckValidFrameChildBehavior's execution logic has been moved:

    Old : public void validate(Object owner, symbol k, MhSnapperChangedEnv env=null) {
    New : public void afterInitialExport(MhSystemCollection system, MhSnapper parent, MhSnapper owner) {

Changes to engine manager

MhRunEngineEnv interface changes:

    Old :
    public constructor(bool cleanup=true, bool blockImport=false, bool blockExport=false,
                       bool blockFinalize=true, bool showProgressBar=false) {
        set*(this: cleanup, blockImport, blockExport, blockFinalize, showProgressBar);
    }

    New :
    public constructor(bool cleanup=true, bool blockImport=false, bool blockExport=false,
                       bool blockFinalize=true, bool removeFailedEntry=true, bool showProgressBar=false) {
        set*(this: cleanup, blockImport, blockExport, blockFinalize, removeFailedEntry, showProgressBar);
    }

MhEngineRun interface changes:

    Old :
    extend public Snapper{} export(MhEngine engine, MhSystemEngineEnvironment env,
                                   MhEngineEntry[] entries, Space space=null) {

    New :
    extend public Snapper{} export(MhEngine engine, MhSystemEngineEnvironment env,
                                   MhEngineEntry[] entries, Space space=null,
                                   MhRunEngineEnv runEnv=null) {

Swapping class inheritance

The MhRowPopulator and MhStorageRowPopulator classes have swapped positions in the parent-child class hierarchy. For classes that extend from MhRowPopulator, they now need to extend from MhStorageRowPopulator.

    Old : public class MhStorageRowPopulator extends MhPopulator
    New : public class MhRowPopulator extends MhPopulator

    Old : public class MhRowPopulator extends MhStorageRowPopulator
    New : public class MhStorageRowPopulator extends MhRowPopulator    

Interface changes in MhRowLayout:

    Old : public MhRowLayout::MhStorageRowPopulator populator;
    New : public MhRowLayout::MhRowPopulator populator;

    Old : extend public MhRowLayout::MhStorageRowPopulator rowPopulator(MhStorageConfiguration config, rect systemRect,
			                                                            	bool isAisle, bool first, bool lastRow) {
    New : extend public MhRowLayout::MhRowPopulator rowPopulator(MhStorageConfiguration config, rect systemRect,
			                                            			 bool isAisle, bool first, bool lastRow) {

Changes to clearance behaviors

MhClearanceBehavior constructor interface change. Now able to set a different purposeKey for clearance behaviors.

    Old : public constructor() { super("Clearance"); }
    New : public constructor(str key="Clearance") { super(key); }

Changes to animation row export

Introduced a new engine function MhAnimRowConstructionalFunction. In 13.5, MhSystemAnimationExportFunction also handled constructing row entries but in 14.0, we have now moved out that functionality into the new class MhAnimRowConstructionalFunction.

The class MhSystemAnimationLevelPopulateExportFunction has also been replaced by MhAnimRowLevelConstructionalFunction.

    Old : res << MhSystemAnimationLevelPopulateExportFunction("animationExport");
    New : res << MhAnimRowLevelConstructionalFunction("animRowConstruction");
    New : res << MhSystemAnimationExportFunction("animationExport");

    Old : public class MhSystemAnimationLevelPopulateExportFunction extends MhSystemAnimationExportFunction {
    New : public class MhAnimRowLevelConstructionalFunction extends MhAnimRowConstructionalFunction {

Important to note is that "animRowConstruction" is executed before "animationExport".

public class MhRowAnimationEngineBehavior extends MhEngineBehavior {

    public void putEngineRunFunctions(MhSnapper snapper, symbol event="", Object env=null) {
        ...
            if (event == sSnapperInserted) {
                bool addFloorLevel = mhStorageConfiguration(snapper).?addFloorLevel();
                mhPutEngineRunFunction(engine, "animRowConstruction", snapper=snapper,
                                       info=info,
                                       holeZDomain=holeZDomain,
                                       addFloorLevel=addFloorLevel,
                                       additionalPrim=additionalPrim);
		
                mhPutEngineRunFunction(engine, "animationExport", snapper=snapper, space=space,
                                       tryConnectToOtherRow=info.tryConnectToOtherRow,
                                       populateOffset=info.unitLoadPopulateOffset(snapper));
	    }
        ...
    }

Check any classes that extend from MhSystemAnimationExportFunction to see if they should be executed before "animationExport". If this is the case, then they should instead extend from MhAnimRowConstructionalFunction. One example of this is MhAnimCantileverConstructionalFunction which used to extend from MhSystemAnimationExportFunction but now extends from MhAnimRowConstructionalFunction.

With these changes, several fields have also been removed from MhSystemAnimationExportFunction.

The fields below have been moved from MhSystemAnimationExportFunction to MhAnimRowConstructionalFunction.

    public SubSet holeZDomain;
    public Bool addFloorLevel;
    public CollisionPrimitive additionalPrim;
    public MhRowAnimationInfo info;

The fields below have been removed from MhSystemAnimationExportFunction without replacement. MhAnimRowConstructionalFunction now retrieves these values directly from the MhRowAnimationInfo field.

    // removed
    public Point pos;
    public Angle rot;

    // MhRowAnimationInfo
    extend public MhEngineConstructionEntry createRowEntry(MhEngineEntryBlock block, MhEngineConstructionEntry e) {
        ...
        point pos = info.p0;
        orientation rot = info.a;
        ...
    }

Unrolling collision primitives

New functions mhUnrollCollisionPrim() which are used to remove roll angles from collision primitives.

/**
 * Unroll primitive transform.
 * Collision resolver does not support rolled primitive.
 */
public CollisionPrimitive mhUnrollCollisionPrim(CollisionPrimitive prim) {
    CollisionPrimitiveSet set(null, null);
    CollisionPrimitive[] prims();
    mhUnrollCollisionPrim(prim, prims);
    for (p in prims) set.subPrims << p;
    return set;
}


/**
 * Unroll collision primitive.
 * @list : result will be appended to the list.
 */
public void mhUnrollCollisionPrim(CollisionPrimitive prim, CollisionPrimitive[] list) : inline {
    if (!list) init list();
    prim.?explode(list);
    for (p in list) if (p.t.rot.roll != 0deg) p.t -= Transform(orientation(0deg, 0deg, p.t.rot.roll));
}

Deprecated MhEngineSnapperEntry::zeroTransformSnapperEntry() method, calls to this method should be replaced with mhUnrollCollisionPrim().

Removed MhLevelPopulateFunction::orientedCollisionEntry() method, calls to this method should be replaced with mhUnrollCollisionPrim().

Changes to mhCalculatedBayHeight()

Two additional parameters have been added to this function.

  • loadWithinLimit : Set this parameter to true to ensure that the calculated bay height includes all unit loads within the bay bound.
  • filter : You can now pass in a SnapperFilter different from mhBayChildrenFilter.
    Old : public <double, int, double> mhCalculatedBayHeight(MhSystemConfigurationItem this, MhSnapper bay, int stepCount,
                                                   double maxBayHeight=maxDouble, bool xtrace=false) {
    New : public <double, int, double> mhCalculatedBayHeight(MhSystemConfigurationItem this, MhSnapper bay, int stepCount,
                                                   bool loadWithinLimit=false,
                                                   SnapperFilter filter=mhBayChildrenFilter,
                                                   double maxBayHeight=maxDouble, bool xtrace=false) {

This function has been updated to support top levels (top level will be processed last by populator). It also better supports non-selective racks (e.g. levels with a roll angle).

Renaming of row width and length

There has been various changes to rename "row width" to "row cross aisle" and "row length" to "row down aisle".

The following classes have been renamed:

    Old : MhRowWidthInsertAnimation
    New : MhRowCrossAisleInsertAnimation

    Old : MhRowLengthInsertAnimation
    New : MhRowDownAisleInsertAnimation

MhRowAnimationInfo interface changes:

// Fields
    Old :
    /**
     * Length. X-axis.
     */
    public double length = 1m;

    New :
    /**
     * Down aisle dimension. X-axis.
     */
    public double downAisleDist = 1m;


    Old :
    /**
     * Width. Y-axis.
     */
    public double width = 1.5m;

    New :
    /**
     * Cross aisle dimension. Y-axis.
     */
    public double crossAisleDist = 1.5m;


    Old :
    public props : cached=false {
        ...
        "length";
        "width";
        ...
    }

    New :
    public props : cached=false {
        ...
        "downAisleDist";
        "crossAisleDist";
        ...
    }


// Methods
    Old : extend public double minRowLength() {
    New : extend public double minRowDownAisleDist() {

    Old : extend public double minRowWidth() {
    New : extend public double minRowCrossAisleDist() {

MhRowInsertAnimation interface changes:

    Old : extend public MhRowLengthInsertAnimation lengthAnimation() {
    New : extend public MhRowDownAisleInsertAnimation lengthAnimation() {

MhRowDownAisleInsertAnimation interface changes:

    Old : extend public MhRowWidthInsertAnimation widthAnimation() {
    New : extend public MhRowCrossAisleInsertAnimation widthAnimation() {

MhRowLayout interface changes:

    Old : public double aisleW;
    New : public double aisleWidth : stream=null;

cm.abstract.materialHandling

    // public class MhSnapperRemoverVessel
    // Consolidated into MhSpreadToolEnv
    Removed field: public MhSnapperSpreadPattern spreadPattern;
    New: extend public MhSnapperSpreadPattern spreadPattern()
    New: extend public MhSnapperSpreadPattern spreadPattern=(MhSnapperSpreadPattern p)

    Removed field: public SpreadPatternGroup currentSpreadGroup;
    New: extend public SpreadPatternGroup currentSpreadGroup()
    New: extend public SpreadPatternGroup currentSpreadGroup=(SpreadPatternGroup g)


    // public class MhSnapperSpreadVessel
    // Consolidated to MhSpreadToolEnv
    Removed field: public MhSnapperSpreadPattern spreadPattern;
    Removed field: public SpreadPatternGroup currentSpreadGroup;

    Old: extend public CoreObject[] getCandidates()
    New: extend public CoreObject{} getCandidates()


    // cachedSpreadSnappers globals and public functions - moved into MhSnapperSpreadVessel
    Removed function: public void clearCachedSpread()
    Removed function: public (CoreObject{}) cachedSpreadSnappers(str key)
    Removed function: public void putToCachedSpreadSnappers(str key, CoreObject{} ss)

    Removed function: public void updateCachedSpreadAfterExplode(Snapper parent, box[] markedInfoBounds, MhSnapper[] explodedChildren, str cacheKey)
    New: extend public void updateSpreadGroupAfterExplode(Snapper parent, box[] markedInfoBounds, MhSnapper[] explodedChildren, str cacheKey)

    // cached spreadgroups globals and public functions - consolidated into MhSpreadToolEnv
    Removed function: public void clearSpreadGroups()
    Removed function: public SpreadPatternGroup spreadGroup(CoreObject[] snappers)
    Removed function: public SpreadPatternGroup addSpreadGroup(str cacheKey, CoreObject[] snappers)


    // public class SpreadPatternGroup
    Removed: public str cacheKey;
    Old: public constructor(str cacheKey, CoreObject[] snappers)
    New: public constructor(str key, CoreObject{} candidates)

    Old: public CoreObject[] snappers();
    New: public CoreObject{} candidates();

    Old: extend public bool sameGroup(CoreObject[] incomings)
    New: xtend public bool sameGroup(CoreObject{} incomings)


    // public class MhSnapperSpreadPattern
    Old: extend public str cacheKey(MhTrySnapAlternative mainAlt, CoreObject{} candidates)
    New: extend public void appendCacheKey(StrBuf buf, SnapAlternative mainAlt, CoreObject{} candidates)

    Removed: extend public MhSnapperInsertEntry[] getCachedEntries(MhTrySnapAlternative mainAlt, CoreObject{} candidates)
    Removed: extend public void cacheEntries(MhTrySnapAlternative mainAlt, CoreObject{} candidates, MhSnapperInsertEntry[] entries)

cm.abstract.materialHandling.behavior

    // globals
    Removed: public mhLazyGlobal MhBehavior mhStdSpreadCacheKeyBehavior = MhSpreadCacheKeyBehavior();


    // public class MhSpreadPatternBehavior extends MhBehavior
    New: extend public MhSnapperSpreadPattern spreadPattern(MhSnapperSpreadPattern current, MhSnapper candidate)
    New: extend public void appendCacheKey(StrBuf buf, MhSnapper main, SnapAlternative alternative, MhSnapperSpreadPattern pattern)

cm.abstract.materialHandling.storage

    // public class MhStorageSystemSpreadPattern
    Removed field: public str->MhSnapperInsertEntry[] cache(); // Moved to SpreadPatternGroup

    // Various SpreadPattern subclasses that existed solely to customize cacheKey
    Removed: public class MhUnitLoadNoSpreadPattern extends MhNoSpreadPattern
    Removed: public class MhUnitLoadBaySpreadPattern extends MhStorageBaySpreadPattern
    Removed: public class MhUnitLoadLevelSpreadPattern extends MhStorageLevelSpreadPattern
    Removed: public class MhUnitLoadRowLevelSpreadPattern extends MhStorageRowLevelSpreadPattern
    Removed: public class MhUnitLoadRowSpreadPattern extends MhStorageRowSpreadPattern
    Removed: public class MhUnitLoadDoubleDeepColumnLevelSpreadPattern extends MhDoubleDeepColumnLevelSpreadPattern
    Removed: public class MhUnitLoadColumnLevelSpreadPattern extends MhStorageColumnLevelSpreadPattern
    Removed: public class MhUnitLoadColumnSpreadPattern extends MhStorageColumnSpreadPattern
    Removed: public class MhUnitLoadSystemSpreadPattern extends MhStorageSystemSpreadPattern

cm.abstract.materialHandling.storage.racking

    Removed: public class MhNamePlateColumnSpreadPattern

cm.abstract.materialHandling.storage.racking.behavior

    Removed: public class MhFlankProtectorSpreadCacheKeyBehavior

    // globals
    Removed: public mhLazyGlobal MhBehavior mhFlankProtectorSpreadCacheKeyBehavior

cm.abstract.unitLoad

Changes to UnitLoad

In UnitLoad, the public field name has been replaced by a private field _name together with public getter and setter methods.

    Old : public str name;
    New : private str _name;
    New : extend public str name() {
    New : extend public str name=(str newName) {

By default, the setter method for _name will trigger mtbhCache() to be rehashed if the unit load is in the cache. This is because unit load name is used in the hash function of mtbhCache() and therefore the hash needs to be updated when name is changed.

    extend public str name=(str newName) {
        bool rehashCache = this in mtbhCache();
        str res = _name = newName;
        if (rehashCache) mhRehashUnitLoadCache();
        return res;
    }

cm.core.msOffice.excel

The class NetObj2DArray in cm.core.msOffice.excel is now deprecated as there is already an identical class in cm.abstract.interop with the exact same functionality.

// cm.core.msOffice.excel.excelObj.cm
Deprecated: public class NetObj2DArray extends NetObj {

cm.core.red3d

Interface classes for creating render jobs have changed, using int64 instead of int where needed to support large render specs.

// cm.core.red3d.redRenderJobEnv.cm, Class: REDRenderEnv
Old: extend public void packageAdded(int total)
New: extend public void packageAdded(int64 total)

Old: extend public void packageProgress(int current)
New: extend public void packageProgress(int64 current)

Old: extend public void packageFinished(int total)
New: extend public void packageFinished(int64 total)

cm.core.red3d.distributed

Interface classes for creating render jobs have changed, using Stream64 instead of Stream to support larger files. And also using int64 instead of int where needed for sizes of large streams/files.

// redRenderFrame.cm, Class: REDRenderFrame
Old: final public void serialize(Stream stream)
New: final public void serialize(Stream64 stream)

// redRenderJob.cm, Class: REDRenderJob
Old: final public void packageProgress(bool first, bool last, int incrProgress, int totalProgress)
New: final public void packageProgress(bool first, bool last, int incrProgress, int64 totalProgress)

// redRenderPackageFactory.cm, Class: REDRenderPackageFactory
Old: public int bytesPacked = 0;
New: public int64 bytesPacked = 0;

Old: final public int totalSize();
New: final public int64 totalSize();

// redRenderSpec.cm, Class: REDRenderSpec
Old: final public bool serialize(Stream stream)
New: final public bool serialize(Stream64 stream)

// renderChore.cm, Class: RenderChore
Old: final public void serialize(Stream stream)
New: final public void serialize(Stream64 stream)

// tile.cm, Class: Tile
Old: extend public void serialize(Stream stream)
Mew: extend public void serialize(Stream64 stream)

// tile.cm, Class: InputTile
Old: extend public void serialize(Stream stream)
New: extend public void serialize(Stream64 stream)

cm.std.photo

In cm/std/photo/photoSnapper.cm an argument has been added to the createNewPhoto method.

Old: final public void createNewPhoto()
New: final public void createNewPhoto(bool loadPhoto=true)

cm.track.probe

Old: public function initAllProbes()
New: public function initProbes()

Old: public function destroyAllProbes()
New: public function destroyProbes()

old: public function probeManager()
new: public function probes()

cm.win

Searchable dropdown popup.

There are two parameters that are affecting this search function in constructor of DropDownTreeView which are searchable and searchThreshold.

  • searchable, the search function will only be enabled if true is passed in, won't be enabled otherwise.
  • searchThreshold, the search function will only be enabled if the count of TreeViewItem in this drop down is larger than the threshold, won't be enabled otherwise.
public class DropDownTreeView extends BasicTreeView {
    public constructor(Window parent,
               ...
		       bool searchable=false, // Added flag to control the search. 
		       int searchThreshold=10, // Threshold when to start the search.
               ...

Added method enableSearch() in 14.0 to DropDownTreeViewPopup, which can be used to toggle search window.

    /**
     * Enable search field.
     */
    extend public void enableSearch(bool searchable=true, int searchThreshold=10) {
	    this.searchable = searchable;
	    if (searchable) {
	        this.searchThreshold = searchThreshold;
	        searchField = defaultSearchField();
	    }
    }

New function to load DIB image from MemoryStream.

There was previously no way to load DIB images from a stream, which forced the developer to first write the image to file and then loading with the URL. Now that shouldn't be a problem anymore with this new function.

/**
 * Load the stream of a jpg or png image to DibImage.
 * 
 * stream       - The sequence of bytes that holds the image, it
 *                should be formatted as a jpg or png file.
 * inlineStream - Write the URL to the image object?
 * props        - The properties on how to read the image.
 *                The stream can be formatted in many ways, this
 *		  object tells the reader how to interpret the data.
 * use          - Is the image going to be used after the current thread
 *                has run its course? Then you should set this to true.
 */
public DibImage dibImage(Stream stream, bool inlineStream=false,
			 ReadImageProps props=dibImageProps,
			 bool use=false) {

    if (!stream) return null;

    if (!props.dibPadding) props = props + ReadImageProps(dibPadding=true);

    ReadImageResult readResult;
    try {
	lastLoadImageErrorCode = 0;
	readResult = imageMagick.read(stream.array,
				      byteCount=stream.count(),
				      pixels=true, blob=false,
				      props=props);

    } catch (OutOfMemory e) {
	lastLoadImageErrorCode = 3;
	return null;
    } catch (Exception e) {
	lastLoadImageErrorCode = 4;
	return null;
    }

    if (!readResult) return null;

    // Not including this test as we still need to read the stream to know the pixel count,
    // so we've already paid the price to performance if we have a gigantic image
    //if (imageAreaLimit > 0 and fileReadable and url.imageSize.area() > imageAreaLimit) throw ImageTooBigException();

    Dib dib();
    if (createDibImageFromDibBytes(readResult.pixels.array,
				   readResult.size.w, readResult.size.h,
				   readResult.channels, dib)) {
	DibImage image(alpha=props.alpha);
	
	image.dib = dib;

	if (!inlineStream) image.file = stream.path;
	
	image.setSize(image.dib.size);
	image.bitDepth = image.dib.bitDepth();
	
	if (use) image.use();
	return image;
    }
    
    return null;
}

custom.catalogBrowser

File moved from custom.catalogBrowser

Some of the files are moved to abstract package to remove dependency to the catalog browser. This means downloaded catalog toolboxed will be visible without having to turned on "Catalog Browser"'s extension.

  • custom/catalogBrowser/schemes.cm file has been moved to abstract package cm/abstract/dataSymbol/scheme/layout/.
  • custom/catalogBrowser/toolboxes.cm file has been moved to abstract package cm/abstract/dataSymbol/toolbox/.

custom.dataCatalog

DcPortfolioDetailsSubWindow's field rename

In custom/dataCatalog/builder/publish/dcPortfolioDetailsSub.cm, embedDD field has been rename to license for clarity.

Old : public DsDropDownTreeView embedDD;
New : public DsDropDownTreeView licenseDD;

Removed dependency from custom.dataCatalog.builder.publish package

Removed dependency from custom.dataCatalog.builder.geometry in custom.dataCatalog.builder.publish

Updates to DcPublishConfirmationDialog

In custom/dataCatalog/builder/publish/dcDeleteConfirmationDialog.cm, added new class DcConfirmationDialog and made DcPublishConfirmationDialog as a subclass of the new class. Also changed the modifier from public to package.

custom.flooring

We've changed almost everything of the flooring extension by refactoring. Flooring was never intended to be inherited. But we have opened it up a bit to allow reading of flooring information.

custom.walkthrough

// REDRenderGIEnv
Old: public void packageAdded(int total)
New: public void packageAdded(int64 total)

Old: public void packageFinished(int total)
New: public void packageFinished(int64 total)

// REDRenderJobEnv
Old: public void packageAdded(int total)
New: public void packageAdded(int64 total)

Old: public void packageProgress(int current)
New: public void packageProgress(int64 current)

Runtime/Behavior Changes

Canvas and Device

Canvas

Canvas implementations that subclass Canvas directly, instead of a more specific implementation like GdiCanvas will find many things not working, since many methods have been moved to ToPixelCanvas. Try subclassing GdiCanvas or ToPixelCanvas instead.

CollabG3 (CollabPro)

Although a local file containing CollUFOFileType is never created, bug() will now be triggered as an additional enforcement in the event it is mistakenly created.

Compiler

Daylight-savings (DST) handling

Time conversion functions throughout various parts of the system were incorrectly handling daylight-savings transitions. This has been fixed.

Object::setField now follows the type rules

The setField method used to permit almost any value type so long as the type of the destination field was assignable to Object. This is a severe violation of the type system's rules and thus in the new version, setField ensures that the type of the instance passed in is assignable to the type of the destination field.

Basically, the same rules that apply to normal field assignment (instance.field = value) now apply to setField (instance.setField("field", value)). There is an exception for unboxing -- for example, you can use setField to set an int field, even though you're passing in an Int, since setField takes an Object.

Example

public class Foo {
    public constructor() {}
    public str->str map_field;
}

{
    Foo f();
    f.setField("map_field", new str->str());    // ok
    f.setField("map_field", new str->Object()); // forbidden in 14.0
}

Changes to severe internal error handling (bail out)

When CM has a severe internal error, it will perform a "bail out". In some circumstances, the bail out may itself cause further errors. In 14.0, many of those situations are now handled by "fast fail" instead. If minidump generation or JIT debugging are configured, they will be invoked, otherwise the application will terminate ungracefully.

Some extremely severe errors (e.g. garbage collector state corruption) may go directly to "fast fail" without a "bail out" attempt, leaving no trace in log files.

Data Variables

When calling a DRecord method that takes the path to a StrArray variable, an additional indexing operator ";;" can now be specified, followed with an integer, to access the value stored at that index.

DRecord root();
root.assign("test.var", StrArray(["one", "two"]));
pln(root.lookupStr("test.var;;1")); // output: two

As a result of this change, the substring ";;" can no longer appear in any part of the path to the variable, and can only appear when accessing a StrArray.

DRecord root();
root.assign("test.var;;1", null); // not allowed
root.assign("test.v;;ar", 3); // not allowed

Floating-point Rounding Behavior

Rounding of floating-point numbers

This is not something introduced in 14.0. This is something introduced in Windows 10 version 2004 (build 19041) which was released May 2020. This is now covered here because it directly affects how floating-point numbers are rounded and has not been mentioned in any migration guide yet.

This update changes the way the fprint-family formats floating-point numbers. Before the mentioned build, floating-point numbers ending in '5' always rounded up. This was changed in May 2020 to always round to the closest even digit (known as Banker's rounding). This to be more in line with IEEE 754.

This affects all methods which in converts a floating-point number into a string.

For example:

Before May 2020:

   formatted(1.45, precision=1)=1.5
   formatted(1.35, precision=1)=1.4

After May 2020 (currently):

   formatted(1.45, precision=1)=1.4
   formatted(1.35, precision=1)=1.4

For more information, read Microsoft's Documentation

Variants Constraints

Certain tags stored in XML will be removed/added in ofdaImport() and ofdaExport(). db3 import and export behaviours will also be affected similarly. Hence, forward compatibility would not be supported i.e., importing a newer XML/db3 file into an older version of CET may not have the correct apply style applied to the catalog.

The following classes are affected:

DataCatalog

Tags removed:

  • ConstraintsApplyStyle
  • ConstraintType

DsRuleType

Tags added:

  • ConstraintExpressionType

cm.abstract

The global private bool _blockedUndoHookCB has been removed from photoSnapper and instead added as a public field in the drawRect parent class. This was done since this value needs to be checked during the drawRectUndoHook. Although it is only used by photoSnapper, it was moved to the parent class to avoid drawRect from needing a dependecy on photoSnapper. In order for the photoSnapper subclass to be able to read and modify its value, it was changed to a public variable.

old: cm/std/photo/photoSnapper.cm

private bool _blockUndoHookCB = false;

new: cm/abstract/draw/drawRect.cm

    /**
     * Block undo hook.
     */
    public bool blockUndoHookCB = false;

As a result we now instead modify this public field in cm/std/photo/photoSnapper.cm quickPropertyChanged():

old:

_blockUndoHookCB = true;
...
_blockUndoHookCB = false;

new:

blockUndoHookCB = true;
...
blockUndoHookCB = false;

As mentioned, the previously named photoSnapperUndoHook has been moved from PhotoSnapper to its parent class DrawRect and renamed drawRectUndoHook. As a result the hook registration has also been moved to the parent class:

cm/std/photo/photoSnapper.cm removed:

/**
 * Photo snapper undo hook.
 */
private void photoSnapperUndoHook(World w, UndoStep step) {
    if (_blockUndoHookCB) return;

    //double start = microTime();
    if (step and step.contains(UndoModifyOp)) {
	if (!w.isUndoRecording and !isUndoRestoreInProgress) {
	    Space{} affected(4);
	    for (PhotoSnapper s in step.modified) {
		if (s.space !in affected and s.space.isPaperSpace() and step.affects(s.space)) {
		    affected << s.space;
		}
	    }

	    if (affected.any) {
		View{} visited(4);
		for (space in affected) {
		    for (REDPaperView view in space.views, index=i) {
			if (view !in visited) {
			    view.invalidatePaperShape();
			    visited << view;
			}
		    }
		}
	    }
	}
    }
    //pln("Invalidate paper shape took: ", us(microTime - start));
}


old:

init {
    putAlternativesChangedHook("cm.std.photo.photoSnapper", function changedAlternativeHook);
    registerUndoHook("photoSnapperUndoHook", function photoSnapperUndoHook);
}

new:

init {
    putAlternativesChangedHook("cm.std.photo.photoSnapper", function changedAlternativeHook);
}

cm/abstract/draw/drawRect.cm added:

use cm.application;

added:

/**
 * Draw rect undo hook.
 */
private void drawRectUndoHook(World w, UndoStep step) {
    if (step and step.contains(UndoModifyOp)) {
	if (!w.isUndoRecording and !isUndoRestoreInProgress) {
	    Space{} affected(4);
	    for (DrawRect s in step.modified) {
		if (s.space !in affected and s.space.isPaperSpace() and step.affects(s.space) and s.drawLayer == bottomLayer and !s.blockUndoHookCB) {
		    affected << s.space;
		}
	    }

	    if (affected.any) {
		View{} visited(4);
		for (space in affected) {
		    for (REDPaperView view in space.views, index=i) {
			if (view !in visited) {
			    view.invalidatePaperShape();
			    visited << view;
			}
		    }
		}
	    }
	}
    }
}

added:

init {
    registerUndoHook("drawRectUndoHook", function drawRectUndoHook);
}

AccessoryEnv

Commit ae48deba In createAccessory() now checks to see if the AccessoryEnv accepts the location instead making a new accessory and asking the location if it accepts the accessory.

Old : 
extend public bool createAccessory(AccGenBehavior behavior, AccLoc loc, CoreObject{} existing) {
 CoreObject acc = generateAccessory(behavior, loc);
  
 if (loc.acceptAccessory(acc)) {
  behavior.updateAccessory(acc, loc);
 ...
 }
 
New :
extend public bool createAccessory(AccGenBehavior behavior, AccLoc loc, CoreObject{} existing) {
 if (acceptLocation(loc)) {
   CoreObject acc = generateAccessory(behavior, loc);
   
   behavior.updateAccessory(acc, loc); 
 ...
 }

COMmaterials

Creating a COMaterial will always create a GMaterial3D. It will use a PBRMatSpec as its spec. Selecting a texture from the COMaterial dialog will set the baseTextureUrl of the spec, while selecting a color from the dialog will set the baseColorFactor of the spec.

cm/abstract/material/comMaterialDialog.cm and cm/abstract/industry/comMaterialDialog.cm:

Constructor:

old:
	    if (!tempMat)
	      tempMat = CustomerOwnMaterial("COMTEMP", "", colorMaterial3D( 125, 125, 125 ));

new:
	    if (!tempMat)
	      tempMat = CustomerOwnMaterial("COMTEMP", "", GMaterial3D());

cm/abstract/material/comMaterialDialog.cm

old:
    extend public void chooseBtnColorCB() {
	color c = chooseColorDialog(parent, tempMat.color2D);
	if (c.isColor) {
	    Material3D m = colorMaterial3D(c);
	    tempMat.updateMaterial3D(m);
	    setControlsEnable();
	    updateImage();
	}

new:

    extend public void chooseBtnColorCB() {
	color c = chooseColorDialog(parent, tempMat.color2D);
	if (c.isColor) {
	    PBRMatSpec spec();
	    spec.baseColorFactor = colorToColorF(c);
	    GMaterial3D m = GMaterial3D(spec);
	    tempMat.updateGMaterial3D(m);
	    setControlsEnable();
	    updateImage();
	}

old:

      extend public void browseUrl() {
	Url url = coreSettings.get("COMaterialDialog.wrappedImageFile").Url;
	int imageFileFilterIdx = coreSettings.safeGetInt("COMaterialDialog.fileFilterIdx");
	
	Int fileFilterIdx(imageFileFilterIdx);
	url = getOpenFileName(this, url, imageImportFilter, filterIndex=fileFilterIdx);
	
	if (url and url.isReadable) {
	    setLastUrlAndIndex(url, fileFilterIdx.v);
	    Material3D m = wrappedImageMaterial3D(url);
	
	    tempMat.updateMaterial3D(m);
	
	    updateImage();
	}

new:

      extend public void browseUrl() {
	Url url = coreSettings.get("COMaterialDialog.wrappedImageFile").Url;
	int imageFileFilterIdx = coreSettings.safeGetInt("COMaterialDialog.fileFilterIdx");
	
	Int fileFilterIdx(imageFileFilterIdx);
	url = getOpenFileName(this, url, imageImportFilter, filterIndex=fileFilterIdx);
	
	if (url and url.isReadable) {
	    setLastUrlAndIndex(url, fileFilterIdx.v);
	    PBRMatSpec spec();
	    spec.baseTextureUrl = url;
	    Material3D m = GMaterial3D(spec);
	
	    tempMat.updateGMaterial3D(m);
	
	    updateImage();
	}

cm/abstract/industry/comMaterialDialog.cm

old:
      extend public void chooseBtnColorCB() {
	 color c = chooseColorDialog(parent, tempMat.color2D);
	 if (c.isColor) {
	     tempMat.invalidate();
	     Material3D m = colorMaterial3D(c);
	     tempMat.updateMaterial3D(m);
	     tempMat._color2D = c;
	 
	     updateImage();
	 }


new:

       extend public void chooseBtnColorCB() {
	 color c = chooseColorDialog(parent, tempMat.color2D);
	 if (c.isColor) {
	     tempMat.invalidate();
	     PBRMatSpec spec();
	     spec.baseColorFactor = colorToColorF(c);
	     GMaterial3D m = GMaterial3D(spec);
	     tempMat.updateGMaterial3D(m);
	 
	     updateImage();
	 }

old:

    extend public void browseUrl() {
	 Url url = coreSettings.get("IndCOMaterialDialog.wrappedImageFile").Url;
	 int imageFileFilterIdx = coreSettings.safeGetInt("IndCOMaterialDialog.fileFilterIdx");

	 Int fileFilterIdx(imageFileFilterIdx);
	 url = getOpenFileName(this, url, imageImportFilter, filterIndex=fileFilterIdx);

	 if (url and url.isReadable) {
	     setLastUrlAndIndex(url, fileFilterIdx.v);
	     Material3D m = wrappedImageMaterial3D(url);
	     tempMat.updateMaterial3D(m);

	     updateImage();
	 }
     }


new:

     extend public void browseUrl() {
	 Url url = coreSettings.get("IndCOMaterialDialog.wrappedImageFile").Url;
	 int imageFileFilterIdx = coreSettings.safeGetInt("IndCOMaterialDialog.fileFilterIdx");

	 Int fileFilterIdx(imageFileFilterIdx);
	 url = getOpenFileName(this, url, imageImportFilter, filterIndex=fileFilterIdx);

	 if (url and url.isReadable) {
	     setLastUrlAndIndex(url, fileFilterIdx.v);
	     PBRMatSpec spec();
	     spec.baseTextureUrl = url;
	     Material3D m = GMaterial3D(spec);
	
	     tempMat.updateGMaterial3D(m);

	     updateImage();
	 }
     }

added:
private str[] gMatImportFilter() {
    return [$fileFilterGMatStr, $fileFilterGMatFilter, 
	    $allFilesFilter, "*.*"];
}

cm/abstract/industry/customerOwnMaterials.cm

added:
   extend public void updateGMaterial3D(Material3D mat) {
	material3D = mat;
	_color2D = nocolor;
    }

cm/std/assetTools/material/lab/mlGMaterial3D.cm

old:
    final public str{} textureLinksToBase() {
	if (?(str{}) links = misc.get("textureLinksToBase")) {
	    return links;
	}
	return null;
    }

new:
   final public str{} textureLinksToBase() {
	if (?(str{}) links = misc.?get("textureLinksToBase")) {
	    return links;
	}
	return null;
    }

cm.abstract.dataSymInterface

Target extension package

Introduced a additional field targetExtensions to store information regarding content pack's extension that being provided by the webservice. This target extension is currently used to check for the extension dependencies and will automatically enabled when user toogle the catalog's state.

New : public str[] targetExtensions();

dsUILevel card item

Additional enum value for dsUILevel is added in 14.0.

public enum dsUILevel : field access {
    ...
    card = 4; // Added for 14.0
}

cm.abstract.dataSymbol

DsPicklist Item Creation

DsPicklistSubWindow now sends all item creation and freeform data creation to the item manager. Previously the item manager would handle some item management and the sub window would handle others.

The following methods/functions were modified.

public void endDrag(pointI p)
public void addFreeformItem(DsFreeformItem freeform) 
public void copyItem()
private void dragAnimationDropCB(DsDragAnimation animation, Window window, pointI p)

cm.abstract.draw

A DrawSurfaceSnapper will now not display path snap points if the member count is 500 or over. This was done to prevent a bug where only some of the snap points would appear if the count was very great.

cm.abstract.k2

K2Creator changes

XpWorktopTypeBehavior has been deprecated* Instead, the thickness property should be defined on the worktop shape, and the material should be defined on the worktop graphics behavior.

K2Worktop2DBehavior, k2Worktop3DBehavior and K2Backsplash2DBehavior have all been deprecated*. Instead a new behavior called K2WorktopGfxBehavior will replace all of them.

*Deprecated behaviors will remain in 14.0 and should keep functioning. But they are planned to be entirely removed in 14.5.

cm.abstract.materialHandling

Engine export

There is now a devmode warning during system export that is printed when an entry is deemed to have failed a consistency check.

    /**
     * Check for consistency. Return true if exported is consistent with entry.
     */
    extend public bool exportFailed(MhEngineEntry entry, box exportedBound) {
        box eb = exportedBound;
        return eb.w != entry.w or eb.d != entry.d or eb.h != entry.h;
    }
    extend public void exportEntry(Space space, MhEngineConstructionEntry entry,
				   MhSnapper parent=null, Snapper{} visited=null) {
        ...
        box eb = info ? info.shape.?engineEntryBound() : s.?engineEntryBound();
        if (exportFailed(entry, eb)) {
            if (developMode) pln("Export failed for ".eRed; entry; entry.classification);
            if (removeFailedEntry.?v) return;
        }
        ...
    }

Unstreaming clearance spec

When loading MhLevelShape and unstreaming the saved MhClearanceSpec, we check existing clearance specs in the MhClearanceSpecContainer of a world. Previously this always checked mainWorld's clearance specs, but this has now been changed to check against the shape owner's world. This change addresses checking against incorrect clearance specs when loading a drawing.

    extend public void unstreamStoredSpec(ObjectFormatter formatter) {
        ...
        Old : if (MhClearanceSpecContainer container = clearanceSpecContainer()) {
        New : if (MhClearanceSpecContainer container = clearanceSpecContainer(owner.?space.world)) {

Changes to MhLevelPopulateFunction

Usage of the limitZ field in MhLevelPopulateFunction has been updated. In 13.5 the accepts() method would immediately check against the limitZ value if it exists, ignoring the maxZ() method. In 14.0 the accepts() method will always call maxZ(), and maxZ() now returns limitZ if it exists.

    extend public bool accepts(MhEngineEntry parent, MhEngineEntry newLevel) {
        ...
        double maxZ = maxZ(parent, prim);
        ...
    }


    extend public double maxZ(MhEngineEntry levelParentEntry, CollisionPrimitive prim) {
        if (limitZ) return limitZ.safeDouble();
    }

Updated the behavior of the accepts() method. It now returns highestZ <= maxZ instead of highestZ < maxZ. Additionally the highestZ calculation when loadWithinLimit=true has been updated.

    Old :
        if (loadWithinLimit.?v) {
            double max = 0;

            if (CollisionPrimitive prim = newLevel.collisionPrim(engine.MhEngine)) {
                max = prim.bound.h;
            } else {
                for (c in newLevel.children(engine.MhEngine)) {
                    double h = c.localBound.h;
                    max = max(max, h);
                }
            }
            highestZ += max;
        }


    New :
        if (loadWithinLimit.?v) {
            double max = 0;
            for (c in newLevel.children(engine.MhEngine)) {
                if (!c.isUnitLoad) continue;
                double h = c.localBound.h;
                max = max(max, h);
            }

            highestZ += max;
        }

Mobile behavior keys

MhMobileFloorUpdateBehavior now has the following key "updateMobileFloorAfterInitialExport". MhMobilePlatformUpdateBehavior now has the following key "updateMobilePlatformAfterInitialExport".

Frame accessory classification

The following spawners have had the sFrameAccessory layer added to their classifications.

  • MhCornerProtectorSpawner
  • MhFlankProtectorSpawner
  • MhUprightProtectorSpawner

MhSnapperMultiApplyAnimation changes

applyToCandidateGroup() no longer always selects the first snapper in the given MhSnapperGroup. It now also checks for and returns the first snapper in the MhSnapperGroup that matches the classification of the selection's main snapper.

    Old:
    extend public void applyToCandidateGroup(MhSnapperGroup grp) {
        if (MhSnapper grpMain = grp.?snappers.get) {
    }


    new:
    extend public void applyToCandidateGroup(MhSnapperGroup grp) {
        if (MhSnapper grpMain = getGrpMain(grp)) {
    }


    /**
     * Get SnapperGroup main.
     */
    extend public MhSnapper getGrpMain(MhSnapperGroup grp) {
        if (!grp) return null;
        for (s in grp.snappers)
          if (s.classification.eval(selection.?main.MhSnapper.classification))
            return s;

        return grp.?snappers.get;
    }

bottomStorageLevel changes

The bottomStorageLevel field in MhBayShape is now only used when the bay has a floor level.

public class MhBayShape extends MhBoxSnapperShape {
    /**
     * HoleZDomain
     */
    extend public SubSet holeZDomain() {
        ...
        if (!hasFloorLevel()) res.minV = res.closestSucceeding(bottomStorageLevel).safeDouble;
        return res;
    }


    /**
     * Append Bottom Storage Primitives
     */
    extend public void appendBottomStoragePrimitives(CollisionPrimitive{} prims, Transform t=null) {
        double floorZ = -1mm; // Under the floor to ensure collition with first level
        Bool actualHasFloorLevel = get("configLoadOnFloor").?Bool;
        if (!actualHasFloorLevel) actualHasFloorLevel = hasFloorLevel();
        double bottomZ = (!actualHasFloorLevel.v ? bottomStorageLevel : 0);
        ...
    }
}


public class MhStorageConfiguration extends MhSystemConfiguration {
    /**
     * HoleZDomain
     */
    extend public SubSet holeZDomain() {
        ...
        double bottomZ = !addFloorLevel() ? bottomStorageLevel.safeDouble : 0;
        res.minV = res.closestSucceeding(bottomZ).safeDouble;
        return res;
    }

Additionally, MhBaySpawner now also returns a loadOnFloor value in shapeCreationProps() from the current configuration.

    /**
     * ShapeCreationProps
     */
    public str->Object shapeCreationProps() {
        if (currentConfig) {
            str->Object res = props { ...
                                      loadOnFloor=currentConfig.addFloorLevel()
        ...
    }

Changes to MhCollisionResolver

MhCollisionResolver now always unrolls collision primitives when they are appended to the resolver. This change was made as collision primitives currently do not support resolving collisions with a roll or pitch angle.

    /**
     * Append fixed.
     */
    public void appendFixed(CollisionPrimitive z) {
        CollisionPrimitive[] list();
        mhUnrollCollisionPrim(z, list);
        for (p in list) fixed << p;
    }


    /**
     * Append.
     */
    public void append(CollisionPrimitive z) {
        CollisionPrimitive[] list();
        mhUnrollCollisionPrim(z, list);
        for (p in list) prims << p;
    }

All previous abstract code that initialized CollisionResolver have been replaced with MhCollisionResolver.

public class MhCollisionAlternative extends MhTrySnapAlternative {
    extend public CollisionResolver collisionResolver(Snapper z) {
        if (!_resolver) _resolver = MhCollisionResolver();
        return _resolver;
    }
}


public class MhSnapperSpreadPattern : abstract {
    extend public SnapAlternative[] snapAlternatives(Snapper candidate, MhTrySnapAlternative mainAlt, MhSnapBehavior[] behaviors) {
        ...
        MhCollisionResolver cr();
        ...
    }
}


// cm/abstract/materialHandling/mhResolverFunctions.cm
public Point resolveNextTo(CollisionPrimitive prim, CollisionPrimitive fixedPrim,
                           CollisionPrimitive additionalPrim, CollisionVectorOption option) {
    ...
    MhCollisionResolver resolver();
    resolver.append(option);
    ...
}
public bool primConflicts(CollisionPrimitive prim, CollisionPrimitive fixedPrim) {
    MhCollisionResolver resolver();
    ...
}

Changes to system configuration

The logic in the load() method (to load a configuration from a file) has been modified. It now calls setItemProps() instead of initItems(). With this change, it will no longer set owner of items, create MhConfigurationItemGroup for items, and it will no longer call item.afterInit(). Additionally there is a new call to afterLoad(), which calls afterConfigLoad() in all items.

    /**
     * After load.
     */
    extend public void afterLoad(RobustFormatter formatter) {
        for (item in _items) {
            item.afterConfigLoad(formatter);
        }
    }

If there is some logic for classes extending from MhSystemConfigurationItem that needs to be done after loading a configuration from a file, you may have previously added that code to afterInit(). You should now override the new method afterConfigLoad() instead.

    /**
     * After configuration load.
     */
    extend public void afterConfigLoad(RobustFormatter formatter) { }

Changes to deep storage level engine behavior

MhDeepstorageLevelEngineBehavior now responds different to the sUnitLoadChanged and sChildShapeChanged events. It will now run "unitLoadPopulate" regardless of what spread pattern is used, so it will no longer run "unitLoadEnsureClearance" instead.

Changes to row selection behavior

MhRowSelectionBehavior has been updated to use the MhRowBackToBackFilter for flue gap rows (excluding double-deep flue gaps). With this change, selecting flue gap rows will now also select the directly connected top and bottom rows.

Changes to MhSnapper rotatable method

MhSnapperShape now has a new method rotatable().

    /**
     * Return true if s is a 'rotation snap'.
     */
    extend public bool rotatable(MhSnapper snapper, Connector s) {
        return true;
    }

This is called from MhSnapper.rotatable().

    /**
     * Return true if s is a 'rotation snap'.
     */
    public bool rotatable(Connector s) {
        if (parent) return false;
        return super(..) and shape.?rotatable(this, s);
    }

Spread pattern changes

  • public class SpreadPatternGroup is now unstreamable.
  • MhSnapper.spreadFilter() now returns null if no MhSpreadSnapperFilterBehavior has been defined. Consider defining the behavior if required.
  • MhTrySnapAlternative now sets lastAlternativeSelected before candidateChanged and candidateChosen to ensure the animation acts on the current information.
  • MhUnitLoadSpreadPatternBehavior.spreadPatternDomain() now returns a ClassSubSet domain of MhStorageXXXXXXXSpreadPattern (old: MhUnitLoadXXXXXXXXSpreadPattern).

cm.abstract.office

AODataSkinFrame

Added code to modifyCopy(CopyEnv cEnv) and to restored(Snapper s) to address an issue where the ModifyEnv system wasn't updating tiles.

cm.application

Changes to cm/application/paperSelectionPanel.cm

old:

final public bool loadPaper(Url path=null) {

	...

	if (selectedSpace) {
	    // Assign the same group to the new space in order to ensure that the paper ordering is correct.
	    if (world.isCollWorldG2()) newSpace.group = selectedSpace.group;
	    if (!world.isCollWorld()) newSpace.setOrderNr(selectedSpace.orderNr);
	}

	createSmallPagePreviewControl(newSpace);

	...
   }

new:

 final public bool loadPaper(Url path=null) {

	...

	if (selectedSpace) {
	    // Assign the same group to the new space in order to ensure that the paper ordering is correct.
	    newSpace.group = selectedSpace.group;
	    newSpace.setOrderNr(selectedSpace.orderNr);
	}

	clearAndRebuild();
	...
   }

The following change makes sure the selected papers are only cloned once:

old:

private void clonePaperCB(Control c) {
    if (PaperSelectionPanel selector = c.container(PaperSelectionPanel).PaperSelectionPanel) {
	logEvent("clonePaper", "paperview");
	PaperSpace[] toClone();
	for (z in selector.inMultiSelect) {
	    toClone << z;
	}
	selector.clonePaper();

	for (z in toClone) {
	    selector.select(z);
	    selector.clonePaper();
	}
    }
}

new:

private void clonePaperCB(Control c) {
    if (PaperSelectionPanel selector = c.container(PaperSelectionPanel).PaperSelectionPanel) {
	logEvent("clonePaper", "paperview");
	PaperSpace[] toClone();
	for (z in selector.inMultiSelect) {
	    toClone << z;
	}

	if (toClone.empty()) selector.clonePaper();

	for (z in toClone) {
	    selector.select(z);
	    selector.clonePaper();
	}
    }
}

Finally, the below line in cm/application/paperUI.cm was changed in order to make tesing easier:

old:

final private SubWindow buildActionPanel(Window parent) {

 ...

 groupButton.hide();

 ...

}

new:

final private SubWindow buildActionPanel(Window parent) {

 ...

 if (!developMode) groupButton.hide(); //Show only for testing.

 ...

}

cm.core

In order to keep the changes of the last paperspace, we need to access the most recent world. In multi-drawing mode, this is straightforward and can be done by accessing the previous world:

cm/std/print/paperspace/paperSpaces.cm

old:
public PaperSpace[] allPaperSpaces(World world, bool createIfNone=true) {
    PaperSpace[] spaces();
    if (!world or !world.spaces) return spaces;

    if (world.isCollWorldG3) createIfNone=false;
    for (space in world.spaces) if (space as PaperSpace) spaces << space;

    if (createIfNone and spaces.count() == 0) {
	spaces << PaperSpace(world, $paperDefaultName, group=null);
	if (DocumentCreator z = currentDocumentCreatorIfAny()) z.visibilityChanged();
    }

    spaces.sort(function paperSpaceDifference, null);

    return spaces;
}


new:
public PaperSpace[] allPaperSpaces(World world, bool createIfNone=true) {
    PaperSpace[] spaces();
    if (!world or !world.spaces) return spaces;

    if (world.isCollWorldG3) createIfNone=false;
    for (space in world.spaces) if (space as PaperSpace) spaces << space;

    if (createIfNone and spaces.count() == 0) {
	PaperSpace newPaperSpace(world, $paperDefaultName, group=null);

	World prevWorld = session.prevWorld();

	if (prevWorld and (PaperSpace prevPaper = prevWorld.getLastPaperSpace())) {
	    newPaperSpace.pageSetup.?assimilate(prevPaper.pageSetup);
	}

	spaces << newPaperSpace;
	if (DocumentCreator z = currentDocumentCreatorIfAny()) z.visibilityChanged();
    }

    spaces.sort(function paperSpaceDifference, null);

    return spaces;
}

In single drawing mode some changes were required in order to be able to access the previous world, which would have otherwise been destroyed before the new paperspace had been created: cm/core/multiWorldManager.cm >>>>>>> b892a94b2ab38fe1f04775d1f9eee139bfae2fd8

old:
    extend public World create(str id=null) {
	// old-tech from before LARGEADDRESSAWARE and 64-bits
	//if (virtualSize() > 1.5GB) { pln(eLtRed, "large virtualSize, ", virtualSize.byteFormat, ", run full gc..."); gc(); pln("done", ePop); }

	if (dbg_undoRestoreInProgress) {
	    ptrace("force reset undo state for interaction");
	    dbg_undoRestoreInProgress = false;
	}

	bool anyWorld = session.anySelectableWorld;
	if (singleDrawingMode and anyWorld) close();

	World world = lowLevelCreateWorld(id=id);
	initialize(world);
	return world;
    }

new:
    extend public World create(str id=null) {
	// old-tech from before LARGEADDRESSAWARE and 64-bits
	//if (virtualSize() > 1.5GB) { pln(eLtRed, "large virtualSize, ", virtualSize.byteFormat, ", run full gc..."); gc(); pln("done", ePop); }

	if (dbg_undoRestoreInProgress) {
	    ptrace("force reset undo state for interaction");
	    dbg_undoRestoreInProgress = false;
	}

	World worldToClose;
	bool anyWorld = session.anySelectableWorld;

	if (singleDrawingMode and anyWorld) {
	    worldToClose = session.mainWorld;
	    worldToClose.?setViewMode(normalViewMode, alert=false);

	    for (v in session.views) {
		v.unlock();
		v.removeClipping();
	    }
	}

	World world = lowLevelCreateWorld(id=id);
	initialize(world);

	if (worldToClose) close(worldToClose);

	return world;
    }

ItemTagInfo

Before 14.0, item tag info map was streamed with world.auxillary under the key "LITINFO". The map has been moved to world.cachedData which is not streamed with the drawing. The itemTags have a reference to their info hence the infos are already streamed with the drawing. The cache is rebuilt on load. Reason for this change is to avoid infos getting stuck in the drawing causing dependencies to extensions.

Block and Category Change

The #1 issue from users at CETX last year was the ability to filter individual items in blocks (for example hiding all objects without the #panel category).

To accomplish this a new category was added cCoreBlockCat that is currently set to #block. This category resides on BlockSnappers. All view modes needs to add the cCoreBlockCat to its categories. Most uses are covered by a change to categoryViewMode(..) and other standard ViewModes were modified to always add the cCoreBlockCat, to ensure as few changes to be done as possible on the manufacturer side. However, do keep these changes in mind as you are migrating and testing for 14.0.

While the category 'cCoreBlockCat` is still available, a last-minute change to 14.0 disabled the category to no longer serve a purpose. This may be revisited.

=======

cm.core.debug

Added check of active when calling profilerStop() which prevents a crash if you are stopping before starting.

cm.core.xclip

We introduce a flag which will be set each frame to indicate if the content should be rebuild or not:

cm/core/xclip/xclipWormholeSnapper2D.cm

    added:
    /**
     * Invalidate clipped snappers.
     */
     public bool inv_clippedGraphicSnappers : copy=null, stream=null, ignore modify notice;


    added:
    /**
     * Update 'scene' to show 'objs'.
     */
    public void updateContent(XClipScene scene, Object{} objs) {
	if (inv_clippedGraphicSnappers) {
	    content2D.?invalidateClippedGraphicsSnappers();
	    inv_clippedGraphicSnappers = false;
	}
	super(..);
    }

We also changed the invalidation to simply set this flag instead of running a costly method each frame:

    old: public void invalidate_clipContent() { inv_clipContent = true; content2D.?invalidateClippedGraphicsSnappers(); inv_beforeMaster	 = true; }


    new: public void invalidate_clipContent() { inv_clipContent = true; inv_clippedGraphicSnappers = true; inv_beforeMaster = true;}

cm.subset

DistanceRange

The closest(Object o) method has been updated to return 'v' instead of 'o' if 'o' was a Number.

Old:
/**
 * Return the closest member to 'o' in this subset.
 */
public Object closest(Object o) {
	...
	
	if (o as Number) {
	    distance v = o.double.distance;
	    if (v < minV) return minV;
	    if (v > maxV) return maxV;
	    return o;
	}
	
	...
}

New:
/**
 * Return the closest member to 'o' in this subset.
 */
public Object closest(Object o) {
	...
	
	if (o as Number) {
	    distance v = o.double.distance;
	    if (v < minV) return minV;
	    if (v > maxV) return maxV;
	    return v;
	}
	
	...
}

cm.win

PaneTreeNode

Nullcheck in PaneTreeNode.toS() preventing access violation.

Loading icons behavior changed in developMode to reflect releaseMode.

If the directory path used to access icons from file didn't have '/' at the end they would appear to work in developMode, but fail in releaseMode. They now fail in developMode as well, to prevent surprises at build.

/**
 * Put icon database finder extension directory if necessary.
 * 
 * k   - Key differentiating icons of different systems.
 *       Typically this is the package of the extension
 *	 that is registering a directory.
 * dir - Path where icons are located.
 *       Typically this looks something like
 *	 "custom/extension-name/res/images/".
 *	 
 *	 NOTE: The directory must end with "/" or it isn't
 *	 going to work in releaseMode.
 */
public void putIconDbExtensionDir(symbol k, str dir) {
    if (k !in iconDB) {

	// This will make the behavior like releaseMode.
	if (developMode and !dir.endsWith('/')) return;

	Url[] locations = cmInstalledAll(dir);
	if (locations.any) {
	    for (l in locations) {
	} else {
	    iconDB.finder(k, cmNative(dir));
	}
	
	//Url completeDir = iconDbExtensionDir(dir);
	//iconDB.finder(k, completeDir);
    }
}

custom.dataCatalog

Added: private str getTruncatedPortDesc(str portfolioDesc);

custom.reconfigs

Part import

Before 14.0, when a drawing's parts were loaded into the Reconfiguration tool, their owners were removed. In 14.0 this has changed to keeping the original owner. Because the Reconfiguration Tool is creating a drawing in the background and extracting the parts to the ReconfigSpace, the owner's dead space have also been replaced with the current ReconfigSpace.

This change was made because of the parts' need of providing a space, which they do by returning their owner's space. Without a space, the user might experience loss of information while doing things like exporting. Without a correct space, things like sorting the article view on adjusted values stop to work.

While working with parts in the Reconfiguration Tool, all parts can be relied on to have the current ReconfigSpace set as their space.

The following code was/is called after a list of parts are imported into the Reconfiguration Tool:

New:
/**
* Post processing part list.
*/
extend private void postProcessList(PartList list) {
    if (!list) return;
    for (p in list.parts) {
	if (list) for (p in list.parts) {
	   if (p.owner) {
	       // Replace the temporary space the parts got when created to the current ReconfigSpace.
	       // The parts need to have their space set to the current ReconfigSpace
	       // for the user to for example be able to sort on adjusted columns.
	       p.owner.space = reconfigCalcSpace();
	   }
	}
    }
    return list;
}

Removed:
/***********************************************************************
 * Post processing
 ***********************************************************************/

/**
 * Post process result parts.
 */
extend public void postProcessResultParts() {
    //ptrace(#newParts.count);
    for (p in newParts.parts) {
	postProcessOrderPart(p, null);
    }

    //ptrace(#reused.count);
    for (k, list in reused) for (row in list.rows) for (p in row.parts) {
	postProcessReusePart(p, null);
    }

    //ptrace(#excess.count);
    for (k, list in excess) for (row in list.rows) for (p in row.parts) {
	postProcessExcessPart(p, null);
    }
}


/**
 * Post process order part, with recursion.
 */
extend public void postProcessOrderPart(Part part, Space orderPartSpace) {
    //ptrace(#part);
    removeOwners(part);
}


/**
 * Post process reuse part, with recursion.
 */
extend public void postProcessReusePart(Part part, Space reusePartSpace) {
    //ptrace(#part);
    removeOwners(part);
}


/**
 * Post process excess part, with recursion.
 */
extend public void postProcessExcessPart(Part part, Space excessPartSpace) {
    //ptrace(#part);
    removeOwners(part);
}


/**
 * Remove owners.
 */
final public void removeOwners(Part part) {
    if (part) {
	// Remove owners in children
	for (c in part.children) if (c) removeOwners(c);

	// Remove in part
	part.data.setOwner(null);
	if ((Snapper{}) set = part.data.owners) set.clear();
    }
}

Miscellaneous

Canvas and Device

See https://git.configura.com/cet/external/base/-/merge_requests/29409

Compiler

Fixed File::getStrLine bugs

This function is no longer prone to infinite loops and properly generates a string of characters, not their ASCII codes.

Logging behaviour improvements

The internal printf wrapper function, which is also used for pln and pnn, should now handle invalid characters by replacing them rather than silently aborting output (and skipping the logfile).

Memory usage analysis tools (cm.runtime.memUsage/"Measure memory usage")

The MemUsage tool has been refactored for better performance and significantly lower memory usage.

Fixed name collision issues between non-interactive and interactive run blocks

Executing code using C-M-SPC (cm-compilation-interact-line) in a file with top-level run blocks used to cause problems due to using the same namespace. This is fixed in 14.0.

Snapper Graph Cache Debug Tool

See https://git.configura.com/cet/external/base/-/merge_requests/29350

cm.abstract.materialHandling

Repository migration

The Material Handling extension (extensions/custom/materialHandling) has been moved to the base repository (base/custom/materialHandling).

The Essential Guarding extension (extensions/custom/guarding) has been moved to the base repoitory (base/custom/guarding).