how can i get ImageBaseShape to rotate?

Sep 4, 2012 at 10:14 PM

currently, evertything else rotates ImageBaseShape  (vectorimage).

how do you implement this?

Coordinator
Sep 5, 2012 at 9:01 AM

You can use the shape Picture (derived from PictureBase) which supports both, rotating and displaying vector graphics.
If you need the "replace colors" capability of the CustomizableImageShape, I would advise to implement this functionality in a class derived from PictureBase.

How to add "Replace color support":

  • Define a color (or get a suitable color like in CustomizableImageShape's methods FindRemapColor / FindReplaceColorCallbackProc)
  • Add a suitable ColorMap to the ImageAttributes of PictureBase before drawing the shape.
  • If you want the user to be able to specify the color to be replaced and you want this color to be persisted, you also have to override IEntity.LoadFields, IEntity.SaveFields and the static GetPropertyDefinitions method.

How to add "Rotate" support:

First, a few words on the concept of shape movement and rotation: The shape calculates its shape and control points always unrotated at 0|0 (center of origin of the coordinate system). Before drawing, the so called "DrawCache" (all flieds and objects required for drawing the shape) is updated by a call to "UpdateDrawCache" (if needed). This is where the shape calculates all (unrotated) points, paths, etc. If the shape was only moved, not resized or rotated, the DrawCache will not be recaculated but transformed to the new position.
Afterwards, a call to "TransformDrawCache" prepares a Matrix object that can be used to transform (translate and rotate) the points and objects needed for drawing.
When dragging control points of rotated shapes, you first have to transform the mouse movement by -Angle and then modify the shape's size and position properties. When modifying sizing properties or angle, the DrawCache has to be cleared by "InvalidateDrawCache" so it will be recalculated next time the shape is drawn.

  • Add an Angle property (value specifies the rotation angle in tenths of degrees)
  • Override the RotateCore method that rotates the shape and its points.
  • Override UpdateDrawCache, TransformDrawCache and InvalidateDrawCache method as needed
  • Override MoveControlPointBy / MoveControlPointByCore and MoveBy / MoveByCore methods as needed
  • Override Draw method
  • Override the GetBoundingRectangle method, which calculates an x axis aligned bounding rectangle around the shape ("tight") or around the shape including all of its control points.
  • Override ContainsPoint and IntersectsWith methods
  • And finally, override IEntity.LoadFields, IEntity.SaveFields and the static GetPropertyDefinitions method in order to add persistency support.
Sep 5, 2012 at 11:39 AM

Thanks much for the information.

I like the [ImageBaseShape] colorReplace feature.

I would like to add rotation support also.

I know you told me to do this:

  • Add an Angle property (value specifies the rotation angle in tenths of degrees)
  • Override the RotateCore method that rotates the shape and its points.
  • Override UpdateDrawCache, TransformDrawCache and InvalidateDrawCache method as needed
  • Override MoveControlPointBy / MoveControlPointByCore and MoveBy / MoveByCore methods as needed
  • Override Draw method
  • Override the GetBoundingRectangle method, which calculates an x axis aligned bounding rectangle around the shape ("tight") or around the shape including all of its control points.
  • Override ContainsPoint and IntersectsWith methods
  • And finally, override IEntity.LoadFields, IEntity.SaveFields and the static GetPropertyDefinitions method in order to add persistency support.

 

I'm not good with system.drawing.  

Can you please give me an example in a new c# [ImageBaseShape.cs] class file?

I know those bullet items above are easy for you, but i have no idea how to implement it myself.

Can you please help???  thx!

 

Coordinator
Sep 5, 2012 at 3:17 PM

Adding rotate support is not so easy and it's a lot of code to write. We plan to do this in a future version but I can't tell you when it will be done.

You can have a look at the code yourself and give it a try (or leave it). You can find the whole NShape source code in "Public Documents\NShape\Source" (there is also a link to the source code in the start menu).

Once again, I think it will be a lot easier to implement the color replacing feature into a shape derived from PictureBase:
Have a look at ImageBasedShape.cs, class CustomizableImageShape, method UpdateImageAttributes. Take the code of this method and integrate it into PictureBase (e.g. into the RecalcDrawCache method, where the ImageAttributes are created) and play around a bit.

If you need information on how to create your own shape library, see these chapters in documentation (sample code included):

  • Programmer Tasks / Developing a New Shape Class / Creating the Shape Class
  • Programmer Tasks / Developing a New Shape Class / Adding Persistency Support
Sep 13, 2012 at 2:26 PM

Can you please give me a custom shape project based on picturebase?

I was going to use ImageBasedShape because you have samples, but you dont have any samples of custom shapes based on picturebase.

Can you give me a quick sample project that creates a custom shape based on picturebase?

Coordinator
Sep 14, 2012 at 12:02 PM
Edited Sep 14, 2012 at 12:04 PM

Start VisualStudio, create a new "Class Library" project and switch the target framework to Framework 2.0. Remember to switch the target platform to "Any CPU". Add the assembly "Dataweb.NShape.dll" (and System.Drawing) to the references and paste the code below into the file "Class1.cs". If you want to load the assembly with the NShape designer, your shape library must be in the same directory as the NShapeDesigner.exe.

using Dataweb.NShape;
using Dataweb.NShape.Advanced;
namespace MyShapeLib {
   
    /* Minimum implementation:
     * - Clone method
     * - CalculatePath
     * - Constructors (protected internal)
     * */
    public class MyShape : PictureBase {
        internal static Shape CreateInstance(ShapeType shapeType, Template template) {
            return new MyShape(shapeType, template);
        }

        /// <override></override>
        public override Shape Clone() {
            Shape result = new MyShape(Type, (Template)null);
            result.CopyFrom(this);
            return result;
        }

        protected internal MyShape(ShapeType shapeType, Template template)
            : base(shapeType, template) {
            Construct();
        }

        protected internal MyShape(ShapeType shapeType, IStyleSet styleSet)
            : base(shapeType, styleSet) {
            Construct();
        }

        private void Construct() {
            // Add your constructor logic here...
        }

    }

    // Needed for registering the shape library with NShape
    public static class NShapeLibraryInitializer {
        public static void Initialize(IRegistrar registrar) {
            // Register library
            registrar.RegisterLibrary(libraryName, preferredRepositoryVersion);
            // Register shape types contained in this library
            registrar.RegisterShapeType(
                new ShapeType("MyShape",
                    libraryName,
                    libraryName,
                    /* The implementation of the CreateShapeDelegate used for creating the shape type */
                    delegate(ShapeType shapeType, Template t) {
                        return new MyShape(shapeType, t);
                    },
                    MyShape.GetPropertyDefinitions,
                    true));
        }

        private const string libraryName = "MyShapeLibrary";
        private const int preferredRepositoryVersion = 1;
    }
}

Sep 14, 2012 at 4:12 PM

Hi Kurt,

I've created 2 files [CustomPicture] and [CustomerPictureBase].

You can download the 2 classes here: h ttps://github.com/alexdoan102/CustomPicture-NShape/zipball/master 

 I've the custompicture shape to load with this registration:
==================== 

registrar.RegisterShapeType(new ShapeType("Door", namespaceName, namespaceName,    
 delegate(ShapeType shapeType, Template t)     
          {                   
CustomPicture result = CustomPicture.CreateInstance(shapeType, t, "Dataweb.NShape.GeneralShapes.Resources.Door.png",
                                                     Assembly.GetExecutingAssembly()); 
                  result.Text = "Door";                   
  return result;               
           }, CustomPicture.GetPropertyDefinitions));

====================

 

Everthing loads good, and i can load the shape with the defaul image of "door".
However I have 2 problems:

   1.) the shape does not autosize to the image on creation. How do i get the shape  bounds to autosize to the image shape on creation?

   2.) How do i set the default fill to "transparent"?

 

Please help.  Thanks much... I think your tool is awesome.

 

Coordinator
Sep 17, 2012 at 9:30 AM

Hi Alex,

simply override the "InitializeToDefault" method in CustomPictureBase or CustomPicture:

        protected internal override void InitializeToDefault(IStyleSet styleSet) {
            base.InitializeToDefault(styleSet);
            FillStyle = styleSet.FillStyles.Transparent;
            FitShapeToImageSize();
        }

Use the given IStyleSet to access the styles in the repository's Design.